Coverage Report

Created: 2025-05-27 17:47

/mnt/user-data/adam/aztec-packages/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield_impl.hpp
Line
Count
Source (jump to first uncovered line)
1
// === AUDIT STATUS ===
2
// internal:    { status: not started, auditors: [], date: YYYY-MM-DD }
3
// external_1:  { status: not started, auditors: [], date: YYYY-MM-DD }
4
// external_2:  { status: not started, auditors: [], date: YYYY-MM-DD }
5
// =====================
6
7
#pragma once
8
9
#include "barretenberg/common/assert.hpp"
10
#include "barretenberg/common/zip_view.hpp"
11
#include "barretenberg/numeric/uint256/uint256.hpp"
12
#include "barretenberg/numeric/uintx/uintx.hpp"
13
#include <tuple>
14
15
#include "../circuit_builders/circuit_builders.hpp"
16
#include "bigfield.hpp"
17
18
#include "../bit_array/bit_array.hpp"
19
#include "../field/field.hpp"
20
#include "barretenberg/transcript/origin_tag.hpp"
21
22
namespace bb::stdlib {
23
24
template <typename Builder, typename T>
25
bigfield<Builder, T>::bigfield(Builder* parent_context)
26
    : context(parent_context)
27
    , binary_basis_limbs{ Limb(bb::fr(0)), Limb(bb::fr(0)), Limb(bb::fr(0)), Limb(bb::fr(0)) }
28
    , prime_basis_limb(context, 0)
29
10.1M
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2EPS4_
Line
Count
Source
29
9.36M
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2EPS4_
Line
Count
Source
29
1.23k
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2EPS6_
Line
Count
Source
29
130
{}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2EPS6_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2EPS4_
Line
Count
Source
29
31.9k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2EPS4_
Line
Count
Source
29
279
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2EPS6_
Line
Count
Source
29
694k
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2EPS6_
Line
Count
Source
29
5.61k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2EPS4_
Line
Count
Source
29
53.0k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2EPS4_
Line
Count
Source
29
115
{}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2EPS6_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2EPS6_
30
31
template <typename Builder, typename T>
32
bigfield<Builder, T>::bigfield(Builder* parent_context, const uint256_t& value)
33
    : context(parent_context)
34
    , binary_basis_limbs{ Limb(bb::fr(value.slice(0, NUM_LIMB_BITS))),
35
                          Limb(bb::fr(value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2))),
36
                          Limb(bb::fr(value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3))),
37
                          Limb(bb::fr(value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4))) }
38
    , prime_basis_limb(context, value)
39
3.03M
{
40
3.03M
    ASSERT(value < modulus);
41
3.03M
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2EPS4_RKNS_7numeric9uint256_tE
Line
Count
Source
39
2.76M
{
40
2.76M
    ASSERT(value < modulus);
41
2.76M
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2EPS4_RKNS_7numeric9uint256_tE
Line
Count
Source
39
824
{
40
824
    ASSERT(value < modulus);
41
824
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2EPS6_RKNS_7numeric9uint256_tE
Line
Count
Source
39
75
{
40
75
    ASSERT(value < modulus);
41
75
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2EPS6_RKNS_7numeric9uint256_tE
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2EPS4_RKNS_7numeric9uint256_tE
Line
Count
Source
39
10.9k
{
40
10.9k
    ASSERT(value < modulus);
41
10.9k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2EPS4_RKNS_7numeric9uint256_tE
Line
Count
Source
39
168
{
40
168
    ASSERT(value < modulus);
41
168
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2EPS6_RKNS_7numeric9uint256_tE
Line
Count
Source
39
243k
{
40
243k
    ASSERT(value < modulus);
41
243k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2EPS6_RKNS_7numeric9uint256_tE
Line
Count
Source
39
3.31k
{
40
3.31k
    ASSERT(value < modulus);
41
3.31k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2EPS4_RKNS_7numeric9uint256_tE
Line
Count
Source
39
16.0k
{
40
16.0k
    ASSERT(value < modulus);
41
16.0k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2EPS4_RKNS_7numeric9uint256_tE
Line
Count
Source
39
103
{
40
103
    ASSERT(value < modulus);
41
103
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2EPS6_RKNS_7numeric9uint256_tE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2EPS6_RKNS_7numeric9uint256_tE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2EPS4_RKNS_7numeric9uint256_tE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2EPS4_RKNS_7numeric9uint256_tE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2EPS6_RKNS_7numeric9uint256_tE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2EPS6_RKNS_7numeric9uint256_tE
42
43
// TODO(https://github.com/AztecProtocol/barretenberg/issues/850): audit the evaluate_linear_identity function
44
template <typename Builder, typename T>
45
bigfield<Builder, T>::bigfield(const field_t<Builder>& low_bits_in,
46
                               const field_t<Builder>& high_bits_in,
47
                               const bool can_overflow,
48
                               const size_t maximum_bitlength)
49
51.7k
{
50
51.7k
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
51.7k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
0
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
51.7k
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
51.7k
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
51.7k
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
0
    field_t<Builder> limb_0(context);
60
0
    field_t<Builder> limb_1(context);
61
0
    field_t<Builder> limb_2(context);
62
0
    field_t<Builder> limb_3(context);
63
51.7k
    if (!low_bits_in.is_constant()) {
64
51.2k
        std::vector<uint32_t> low_accumulator;
65
51.2k
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
51.2k
            const auto limb_witnesses =
68
51.2k
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
51.2k
            limb_0.witness_index = limb_witnesses[0];
70
51.2k
            limb_1.witness_index = limb_witnesses[1];
71
51.2k
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
51.2k
        } else {
84
51.2k
            size_t mid_index;
85
51.2k
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
51.2k
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
51.2k
                                                                         "bigfield: low_bits_in too large.");
88
51.2k
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
51.2k
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
51.2k
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
51.2k
        }
95
51.2k
    } else {
96
468
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
468
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
468
        limb_0 = field_t(context, bb::fr(slice_0));
99
468
        limb_1 = field_t(context, bb::fr(slice_1));
100
468
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
51.7k
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
51.7k
    if (maximum_bitlength > 0) {
109
468
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
0
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
0
    }
112
    // We create the high limb values similar to the low limb ones above
113
0
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
51.7k
    if (!high_bits_in.is_constant()) {
115
116
51.2k
        std::vector<uint32_t> high_accumulator;
117
51.2k
        if constexpr (HasPlookup<Builder>) {
118
51.2k
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
51.2k
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
51.2k
            limb_2.witness_index = limb_witnesses[0];
121
51.2k
            limb_3.witness_index = limb_witnesses[1];
122
51.2k
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
51.2k
        } else {
125
51.2k
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
51.2k
                                                                          static_cast<size_t>(num_high_limb_bits),
127
51.2k
                                                                          "bigfield: high_bits_in too large.");
128
129
51.2k
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
51.2k
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
51.2k
        }
132
51.2k
    } else {
133
468
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
468
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
468
        limb_2 = field_t(context, bb::fr(slice_2));
136
468
        limb_3 = field_t(context, bb::fr(slice_3));
137
468
    }
138
0
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
0
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
0
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
51.7k
    if (maximum_bitlength > 0) {
142
468
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
468
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
51.2k
    } else {
145
51.2k
        binary_basis_limbs[3] =
146
51.2k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
51.2k
    }
148
0
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
0
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
0
    set_origin_tag(new_tag);
151
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2ERKNS0_7field_tIS4_EESA_bm
Line
Count
Source
49
43.0k
{
50
43.0k
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
43.0k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
43.0k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
43.0k
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
43.0k
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
43.0k
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
43.0k
    field_t<Builder> limb_0(context);
60
43.0k
    field_t<Builder> limb_1(context);
61
43.0k
    field_t<Builder> limb_2(context);
62
43.0k
    field_t<Builder> limb_3(context);
63
43.0k
    if (!low_bits_in.is_constant()) {
64
42.9k
        std::vector<uint32_t> low_accumulator;
65
42.9k
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
42.9k
            const auto limb_witnesses =
68
42.9k
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
42.9k
            limb_0.witness_index = limb_witnesses[0];
70
42.9k
            limb_1.witness_index = limb_witnesses[1];
71
42.9k
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
42.9k
        } else {
84
42.9k
            size_t mid_index;
85
42.9k
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
42.9k
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
42.9k
                                                                         "bigfield: low_bits_in too large.");
88
42.9k
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
42.9k
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
42.9k
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
42.9k
        }
95
42.9k
    } else {
96
9
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
9
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
9
        limb_0 = field_t(context, bb::fr(slice_0));
99
9
        limb_1 = field_t(context, bb::fr(slice_1));
100
9
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
43.0k
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
43.0k
    if (maximum_bitlength > 0) {
109
136
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
136
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
136
    }
112
    // We create the high limb values similar to the low limb ones above
113
43.0k
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
43.0k
    if (!high_bits_in.is_constant()) {
115
116
42.9k
        std::vector<uint32_t> high_accumulator;
117
42.9k
        if constexpr (HasPlookup<Builder>) {
118
42.9k
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
42.9k
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
42.9k
            limb_2.witness_index = limb_witnesses[0];
121
42.9k
            limb_3.witness_index = limb_witnesses[1];
122
42.9k
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
42.9k
        } else {
125
42.9k
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
42.9k
                                                                          static_cast<size_t>(num_high_limb_bits),
127
42.9k
                                                                          "bigfield: high_bits_in too large.");
128
129
42.9k
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
42.9k
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
42.9k
        }
132
42.9k
    } else {
133
9
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
9
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
9
        limb_2 = field_t(context, bb::fr(slice_2));
136
9
        limb_3 = field_t(context, bb::fr(slice_3));
137
9
    }
138
43.0k
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
43.0k
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
43.0k
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
43.0k
    if (maximum_bitlength > 0) {
142
136
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
136
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
42.8k
    } else {
145
42.8k
        binary_basis_limbs[3] =
146
42.8k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
42.8k
    }
148
43.0k
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
43.0k
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
43.0k
    set_origin_tag(new_tag);
151
43.0k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2ERKNS0_7field_tIS4_EESA_bm
Line
Count
Source
49
1.29k
{
50
1.29k
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
1.29k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
1.29k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
1.29k
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
1.29k
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
1.29k
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
1.29k
    field_t<Builder> limb_0(context);
60
1.29k
    field_t<Builder> limb_1(context);
61
1.29k
    field_t<Builder> limb_2(context);
62
1.29k
    field_t<Builder> limb_3(context);
63
1.29k
    if (!low_bits_in.is_constant()) {
64
1.29k
        std::vector<uint32_t> low_accumulator;
65
1.29k
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
1.29k
            const auto limb_witnesses =
68
1.29k
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
1.29k
            limb_0.witness_index = limb_witnesses[0];
70
1.29k
            limb_1.witness_index = limb_witnesses[1];
71
1.29k
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
1.29k
        } else {
84
1.29k
            size_t mid_index;
85
1.29k
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
1.29k
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
1.29k
                                                                         "bigfield: low_bits_in too large.");
88
1.29k
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
1.29k
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
1.29k
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
1.29k
        }
95
1.29k
    } else {
96
0
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
0
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
0
        limb_0 = field_t(context, bb::fr(slice_0));
99
0
        limb_1 = field_t(context, bb::fr(slice_1));
100
0
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
1.29k
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
1.29k
    if (maximum_bitlength > 0) {
109
322
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
322
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
322
    }
112
    // We create the high limb values similar to the low limb ones above
113
1.29k
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
1.29k
    if (!high_bits_in.is_constant()) {
115
116
1.29k
        std::vector<uint32_t> high_accumulator;
117
1.29k
        if constexpr (HasPlookup<Builder>) {
118
1.29k
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
1.29k
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
1.29k
            limb_2.witness_index = limb_witnesses[0];
121
1.29k
            limb_3.witness_index = limb_witnesses[1];
122
1.29k
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
1.29k
        } else {
125
1.29k
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
1.29k
                                                                          static_cast<size_t>(num_high_limb_bits),
127
1.29k
                                                                          "bigfield: high_bits_in too large.");
128
129
1.29k
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
1.29k
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
1.29k
        }
132
1.29k
    } else {
133
0
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
0
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
0
        limb_2 = field_t(context, bb::fr(slice_2));
136
0
        limb_3 = field_t(context, bb::fr(slice_3));
137
0
    }
138
1.29k
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
1.29k
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
1.29k
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
1.29k
    if (maximum_bitlength > 0) {
142
322
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
322
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
971
    } else {
145
971
        binary_basis_limbs[3] =
146
971
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
971
    }
148
1.29k
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
1.29k
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
1.29k
    set_origin_tag(new_tag);
151
1.29k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2ERKNS0_7field_tIS6_EESC_bm
Line
Count
Source
49
1.88k
{
50
1.88k
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
1.88k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
1.88k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
1.88k
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
1.88k
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
1.88k
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
1.88k
    field_t<Builder> limb_0(context);
60
1.88k
    field_t<Builder> limb_1(context);
61
1.88k
    field_t<Builder> limb_2(context);
62
1.88k
    field_t<Builder> limb_3(context);
63
1.88k
    if (!low_bits_in.is_constant()) {
64
1.88k
        std::vector<uint32_t> low_accumulator;
65
1.88k
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
1.88k
            const auto limb_witnesses =
68
1.88k
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
1.88k
            limb_0.witness_index = limb_witnesses[0];
70
1.88k
            limb_1.witness_index = limb_witnesses[1];
71
1.88k
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
1.88k
        } else {
84
1.88k
            size_t mid_index;
85
1.88k
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
1.88k
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
1.88k
                                                                         "bigfield: low_bits_in too large.");
88
1.88k
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
1.88k
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
1.88k
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
1.88k
        }
95
1.88k
    } else {
96
9
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
9
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
9
        limb_0 = field_t(context, bb::fr(slice_0));
99
9
        limb_1 = field_t(context, bb::fr(slice_1));
100
9
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
1.88k
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
1.88k
    if (maximum_bitlength > 0) {
109
0
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
0
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
0
    }
112
    // We create the high limb values similar to the low limb ones above
113
1.88k
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
1.88k
    if (!high_bits_in.is_constant()) {
115
116
1.88k
        std::vector<uint32_t> high_accumulator;
117
1.88k
        if constexpr (HasPlookup<Builder>) {
118
1.88k
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
1.88k
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
1.88k
            limb_2.witness_index = limb_witnesses[0];
121
1.88k
            limb_3.witness_index = limb_witnesses[1];
122
1.88k
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
1.88k
        } else {
125
1.88k
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
1.88k
                                                                          static_cast<size_t>(num_high_limb_bits),
127
1.88k
                                                                          "bigfield: high_bits_in too large.");
128
129
1.88k
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
1.88k
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
1.88k
        }
132
1.88k
    } else {
133
9
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
9
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
9
        limb_2 = field_t(context, bb::fr(slice_2));
136
9
        limb_3 = field_t(context, bb::fr(slice_3));
137
9
    }
138
1.88k
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
1.88k
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
1.88k
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
1.88k
    if (maximum_bitlength > 0) {
142
0
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
0
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
1.88k
    } else {
145
1.88k
        binary_basis_limbs[3] =
146
1.88k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
1.88k
    }
148
1.88k
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
1.88k
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
1.88k
    set_origin_tag(new_tag);
151
1.88k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2ERKNS0_7field_tIS6_EESB_bm
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2ERKNS0_7field_tIS4_EESB_bm
Line
Count
Source
49
166
{
50
166
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
166
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
166
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
166
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
166
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
166
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
166
    field_t<Builder> limb_0(context);
60
166
    field_t<Builder> limb_1(context);
61
166
    field_t<Builder> limb_2(context);
62
166
    field_t<Builder> limb_3(context);
63
166
    if (!low_bits_in.is_constant()) {
64
160
        std::vector<uint32_t> low_accumulator;
65
160
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
160
            const auto limb_witnesses =
68
160
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
160
            limb_0.witness_index = limb_witnesses[0];
70
160
            limb_1.witness_index = limb_witnesses[1];
71
160
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
160
        } else {
84
160
            size_t mid_index;
85
160
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
160
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
160
                                                                         "bigfield: low_bits_in too large.");
88
160
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
160
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
160
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
160
        }
95
160
    } else {
96
6
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
6
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
6
        limb_0 = field_t(context, bb::fr(slice_0));
99
6
        limb_1 = field_t(context, bb::fr(slice_1));
100
6
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
166
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
166
    if (maximum_bitlength > 0) {
109
0
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
0
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
0
    }
112
    // We create the high limb values similar to the low limb ones above
113
166
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
166
    if (!high_bits_in.is_constant()) {
115
116
160
        std::vector<uint32_t> high_accumulator;
117
160
        if constexpr (HasPlookup<Builder>) {
118
160
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
160
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
160
            limb_2.witness_index = limb_witnesses[0];
121
160
            limb_3.witness_index = limb_witnesses[1];
122
160
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
160
        } else {
125
160
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
160
                                                                          static_cast<size_t>(num_high_limb_bits),
127
160
                                                                          "bigfield: high_bits_in too large.");
128
129
160
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
160
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
160
        }
132
160
    } else {
133
6
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
6
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
6
        limb_2 = field_t(context, bb::fr(slice_2));
136
6
        limb_3 = field_t(context, bb::fr(slice_3));
137
6
    }
138
166
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
166
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
166
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
166
    if (maximum_bitlength > 0) {
142
0
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
0
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
166
    } else {
145
166
        binary_basis_limbs[3] =
146
166
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
166
    }
148
166
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
166
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
166
    set_origin_tag(new_tag);
151
166
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2ERKNS0_7field_tIS4_EESB_bm
Line
Count
Source
49
72
{
50
72
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
72
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
72
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
72
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
72
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
72
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
72
    field_t<Builder> limb_0(context);
60
72
    field_t<Builder> limb_1(context);
61
72
    field_t<Builder> limb_2(context);
62
72
    field_t<Builder> limb_3(context);
63
72
    if (!low_bits_in.is_constant()) {
64
60
        std::vector<uint32_t> low_accumulator;
65
60
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
60
            const auto limb_witnesses =
68
60
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
60
            limb_0.witness_index = limb_witnesses[0];
70
60
            limb_1.witness_index = limb_witnesses[1];
71
60
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
60
        } else {
84
60
            size_t mid_index;
85
60
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
60
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
60
                                                                         "bigfield: low_bits_in too large.");
88
60
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
60
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
60
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
60
        }
95
60
    } else {
96
12
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
12
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
12
        limb_0 = field_t(context, bb::fr(slice_0));
99
12
        limb_1 = field_t(context, bb::fr(slice_1));
100
12
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
72
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
72
    if (maximum_bitlength > 0) {
109
0
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
0
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
0
    }
112
    // We create the high limb values similar to the low limb ones above
113
72
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
72
    if (!high_bits_in.is_constant()) {
115
116
60
        std::vector<uint32_t> high_accumulator;
117
60
        if constexpr (HasPlookup<Builder>) {
118
60
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
60
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
60
            limb_2.witness_index = limb_witnesses[0];
121
60
            limb_3.witness_index = limb_witnesses[1];
122
60
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
60
        } else {
125
60
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
60
                                                                          static_cast<size_t>(num_high_limb_bits),
127
60
                                                                          "bigfield: high_bits_in too large.");
128
129
60
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
60
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
60
        }
132
60
    } else {
133
12
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
12
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
12
        limb_2 = field_t(context, bb::fr(slice_2));
136
12
        limb_3 = field_t(context, bb::fr(slice_3));
137
12
    }
138
72
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
72
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
72
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
72
    if (maximum_bitlength > 0) {
142
0
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
0
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
72
    } else {
145
72
        binary_basis_limbs[3] =
146
72
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
72
    }
148
72
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
72
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
72
    set_origin_tag(new_tag);
151
72
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2ERKNS0_7field_tIS6_EESD_bm
Line
Count
Source
49
3.74k
{
50
3.74k
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
3.74k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
3.74k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
3.74k
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
3.74k
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
3.74k
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
3.74k
    field_t<Builder> limb_0(context);
60
3.74k
    field_t<Builder> limb_1(context);
61
3.74k
    field_t<Builder> limb_2(context);
62
3.74k
    field_t<Builder> limb_3(context);
63
3.74k
    if (!low_bits_in.is_constant()) {
64
3.60k
        std::vector<uint32_t> low_accumulator;
65
3.60k
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
3.60k
            const auto limb_witnesses =
68
3.60k
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
3.60k
            limb_0.witness_index = limb_witnesses[0];
70
3.60k
            limb_1.witness_index = limb_witnesses[1];
71
3.60k
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
3.60k
        } else {
84
3.60k
            size_t mid_index;
85
3.60k
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
3.60k
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
3.60k
                                                                         "bigfield: low_bits_in too large.");
88
3.60k
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
3.60k
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
3.60k
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
3.60k
        }
95
3.60k
    } else {
96
144
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
144
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
144
        limb_0 = field_t(context, bb::fr(slice_0));
99
144
        limb_1 = field_t(context, bb::fr(slice_1));
100
144
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
3.74k
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
3.74k
    if (maximum_bitlength > 0) {
109
0
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
0
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
0
    }
112
    // We create the high limb values similar to the low limb ones above
113
3.74k
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
3.74k
    if (!high_bits_in.is_constant()) {
115
116
3.60k
        std::vector<uint32_t> high_accumulator;
117
3.60k
        if constexpr (HasPlookup<Builder>) {
118
3.60k
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
3.60k
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
3.60k
            limb_2.witness_index = limb_witnesses[0];
121
3.60k
            limb_3.witness_index = limb_witnesses[1];
122
3.60k
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
3.60k
        } else {
125
3.60k
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
3.60k
                                                                          static_cast<size_t>(num_high_limb_bits),
127
3.60k
                                                                          "bigfield: high_bits_in too large.");
128
129
3.60k
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
3.60k
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
3.60k
        }
132
3.60k
    } else {
133
144
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
144
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
144
        limb_2 = field_t(context, bb::fr(slice_2));
136
144
        limb_3 = field_t(context, bb::fr(slice_3));
137
144
    }
138
3.74k
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
3.74k
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
3.74k
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
3.74k
    if (maximum_bitlength > 0) {
142
0
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
0
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
3.74k
    } else {
145
3.74k
        binary_basis_limbs[3] =
146
3.74k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
3.74k
    }
148
3.74k
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
3.74k
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
3.74k
    set_origin_tag(new_tag);
151
3.74k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2ERKNS0_7field_tIS6_EESD_bm
Line
Count
Source
49
1.44k
{
50
1.44k
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
1.44k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
1.44k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
1.44k
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
1.44k
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
1.44k
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
1.44k
    field_t<Builder> limb_0(context);
60
1.44k
    field_t<Builder> limb_1(context);
61
1.44k
    field_t<Builder> limb_2(context);
62
1.44k
    field_t<Builder> limb_3(context);
63
1.44k
    if (!low_bits_in.is_constant()) {
64
1.15k
        std::vector<uint32_t> low_accumulator;
65
1.15k
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
1.15k
            const auto limb_witnesses =
68
1.15k
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
1.15k
            limb_0.witness_index = limb_witnesses[0];
70
1.15k
            limb_1.witness_index = limb_witnesses[1];
71
1.15k
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
1.15k
        } else {
84
1.15k
            size_t mid_index;
85
1.15k
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
1.15k
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
1.15k
                                                                         "bigfield: low_bits_in too large.");
88
1.15k
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
1.15k
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
1.15k
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
1.15k
        }
95
1.15k
    } else {
96
288
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
288
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
288
        limb_0 = field_t(context, bb::fr(slice_0));
99
288
        limb_1 = field_t(context, bb::fr(slice_1));
100
288
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
1.44k
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
1.44k
    if (maximum_bitlength > 0) {
109
0
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
0
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
0
    }
112
    // We create the high limb values similar to the low limb ones above
113
1.44k
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
1.44k
    if (!high_bits_in.is_constant()) {
115
116
1.15k
        std::vector<uint32_t> high_accumulator;
117
1.15k
        if constexpr (HasPlookup<Builder>) {
118
1.15k
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
1.15k
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
1.15k
            limb_2.witness_index = limb_witnesses[0];
121
1.15k
            limb_3.witness_index = limb_witnesses[1];
122
1.15k
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
1.15k
        } else {
125
1.15k
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
1.15k
                                                                          static_cast<size_t>(num_high_limb_bits),
127
1.15k
                                                                          "bigfield: high_bits_in too large.");
128
129
1.15k
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
1.15k
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
1.15k
        }
132
1.15k
    } else {
133
288
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
288
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
288
        limb_2 = field_t(context, bb::fr(slice_2));
136
288
        limb_3 = field_t(context, bb::fr(slice_3));
137
288
    }
138
1.44k
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
1.44k
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
1.44k
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
1.44k
    if (maximum_bitlength > 0) {
142
0
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
0
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
1.44k
    } else {
145
1.44k
        binary_basis_limbs[3] =
146
1.44k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
1.44k
    }
148
1.44k
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
1.44k
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
1.44k
    set_origin_tag(new_tag);
151
1.44k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2ERKNS0_7field_tIS4_EESB_bm
Line
Count
Source
49
45
{
50
45
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
45
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
45
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
45
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
45
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
45
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
45
    field_t<Builder> limb_0(context);
60
45
    field_t<Builder> limb_1(context);
61
45
    field_t<Builder> limb_2(context);
62
45
    field_t<Builder> limb_3(context);
63
45
    if (!low_bits_in.is_constant()) {
64
45
        std::vector<uint32_t> low_accumulator;
65
45
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
45
            const auto limb_witnesses =
68
45
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
45
            limb_0.witness_index = limb_witnesses[0];
70
45
            limb_1.witness_index = limb_witnesses[1];
71
45
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
45
        } else {
84
45
            size_t mid_index;
85
45
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
45
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
45
                                                                         "bigfield: low_bits_in too large.");
88
45
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
45
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
45
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
45
        }
95
45
    } else {
96
0
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
0
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
0
        limb_0 = field_t(context, bb::fr(slice_0));
99
0
        limb_1 = field_t(context, bb::fr(slice_1));
100
0
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
45
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
45
    if (maximum_bitlength > 0) {
109
0
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
0
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
0
    }
112
    // We create the high limb values similar to the low limb ones above
113
45
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
45
    if (!high_bits_in.is_constant()) {
115
116
45
        std::vector<uint32_t> high_accumulator;
117
45
        if constexpr (HasPlookup<Builder>) {
118
45
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
45
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
45
            limb_2.witness_index = limb_witnesses[0];
121
45
            limb_3.witness_index = limb_witnesses[1];
122
45
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
45
        } else {
125
45
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
45
                                                                          static_cast<size_t>(num_high_limb_bits),
127
45
                                                                          "bigfield: high_bits_in too large.");
128
129
45
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
45
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
45
        }
132
45
    } else {
133
0
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
0
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
0
        limb_2 = field_t(context, bb::fr(slice_2));
136
0
        limb_3 = field_t(context, bb::fr(slice_3));
137
0
    }
138
45
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
45
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
45
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
45
    if (maximum_bitlength > 0) {
142
0
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
0
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
45
    } else {
145
45
        binary_basis_limbs[3] =
146
45
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
45
    }
148
45
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
45
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
45
    set_origin_tag(new_tag);
151
45
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2ERKNS0_7field_tIS4_EESB_bm
Line
Count
Source
49
50
{
50
50
    ASSERT(low_bits_in.is_constant() == high_bits_in.is_constant());
51
50
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
52
50
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
53
54
    // Check that the values of two parts are within specified bounds
55
50
    ASSERT(uint256_t(low_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
56
50
    ASSERT(uint256_t(high_bits_in.get_value()) < (uint256_t(1) << (NUM_LIMB_BITS * 2)));
57
58
50
    context = low_bits_in.context == nullptr ? high_bits_in.context : low_bits_in.context;
59
50
    field_t<Builder> limb_0(context);
60
50
    field_t<Builder> limb_1(context);
61
50
    field_t<Builder> limb_2(context);
62
50
    field_t<Builder> limb_3(context);
63
50
    if (!low_bits_in.is_constant()) {
64
50
        std::vector<uint32_t> low_accumulator;
65
50
        if constexpr (HasPlookup<Builder>) {
66
            // MERGE NOTE: this was the if constexpr block introduced in ecebe7643
67
50
            const auto limb_witnesses =
68
50
                context->decompose_non_native_field_double_width_limb(low_bits_in.get_normalized_witness_index());
69
50
            limb_0.witness_index = limb_witnesses[0];
70
50
            limb_1.witness_index = limb_witnesses[1];
71
50
            field_t<Builder>::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t<Builder>(0));
72
73
            // // Enforce that low_bits_in indeed only contains 2*NUM_LIMB_BITS bits
74
            // low_accumulator = context->decompose_into_default_range(low_bits_in.witness_index,
75
            //                                                         static_cast<size_t>(NUM_LIMB_BITS * 2));
76
            // // If this doesn't hold we're using a default plookup range size that doesn't work well with the limb
77
            // size
78
            // // here
79
            // ASSERT(low_accumulator.size() % 2 == 0);
80
            // size_t mid_index = low_accumulator.size() / 2 - 1;
81
            // limb_0.witness_index = low_accumulator[mid_index]; // Q:safer to just slice this from low_bits_in?
82
            // limb_1 = (low_bits_in - limb_0) * shift_right_1;
83
50
        } else {
84
50
            size_t mid_index;
85
50
            low_accumulator = context->decompose_into_base4_accumulators(low_bits_in.get_normalized_witness_index(),
86
50
                                                                         static_cast<size_t>(NUM_LIMB_BITS * 2),
87
50
                                                                         "bigfield: low_bits_in too large.");
88
50
            mid_index = static_cast<size_t>((NUM_LIMB_BITS / 2) - 1);
89
            // Range constraint returns an array of partial sums, midpoint will happen to hold the big limb
90
            // value
91
50
            limb_1.witness_index = low_accumulator[mid_index];
92
            // We can get the first half bits of low_bits_in from the variables we already created
93
50
            limb_0 = (low_bits_in - (limb_1 * shift_1));
94
50
        }
95
50
    } else {
96
0
        uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
97
0
        uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS);
98
0
        limb_0 = field_t(context, bb::fr(slice_0));
99
0
        limb_1 = field_t(context, bb::fr(slice_1));
100
0
    }
101
102
    // If we wish to continue working with this element with lazy reductions - i.e. not moding out again after each
103
    // addition we apply a more limited range - 2^s for smallest s such that p<2^s (this is the case can_overflow ==
104
    // false)
105
50
    uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
106
107
    // if maximum_bitlength is set, this supercedes can_overflow
108
50
    if (maximum_bitlength > 0) {
109
10
        ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
110
10
        num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
111
10
    }
112
    // We create the high limb values similar to the low limb ones above
113
50
    const uint64_t num_high_limb_bits = NUM_LIMB_BITS + num_last_limb_bits;
114
50
    if (!high_bits_in.is_constant()) {
115
116
50
        std::vector<uint32_t> high_accumulator;
117
50
        if constexpr (HasPlookup<Builder>) {
118
50
            const auto limb_witnesses = context->decompose_non_native_field_double_width_limb(
119
50
                high_bits_in.get_normalized_witness_index(), (size_t)num_high_limb_bits);
120
50
            limb_2.witness_index = limb_witnesses[0];
121
50
            limb_3.witness_index = limb_witnesses[1];
122
50
            field_t<Builder>::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t<Builder>(0));
123
124
50
        } else {
125
50
            high_accumulator = context->decompose_into_base4_accumulators(high_bits_in.get_normalized_witness_index(),
126
50
                                                                          static_cast<size_t>(num_high_limb_bits),
127
50
                                                                          "bigfield: high_bits_in too large.");
128
129
50
            limb_3.witness_index = high_accumulator[static_cast<size_t>(((num_last_limb_bits + 1) / 2) - 1)];
130
50
            limb_2 = (high_bits_in - (limb_3 * shift_1));
131
50
        }
132
50
    } else {
133
0
        uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS);
134
0
        uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits);
135
0
        limb_2 = field_t(context, bb::fr(slice_2));
136
0
        limb_3 = field_t(context, bb::fr(slice_3));
137
0
    }
138
50
    binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
139
50
    binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
140
50
    binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
141
50
    if (maximum_bitlength > 0) {
142
10
        uint256_t max_limb_value = (uint256_t(1) << (maximum_bitlength - (3 * NUM_LIMB_BITS))) - 1;
143
10
        binary_basis_limbs[3] = Limb(limb_3, max_limb_value);
144
40
    } else {
145
40
        binary_basis_limbs[3] =
146
40
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
147
40
    }
148
50
    prime_basis_limb = low_bits_in + (high_bits_in * shift_2);
149
50
    auto new_tag = OriginTag(low_bits_in.tag, high_bits_in.tag);
150
50
    set_origin_tag(new_tag);
151
50
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2ERKNS0_7field_tIS6_EESD_bm
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2ERKNS0_7field_tIS6_EESD_bm
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2ERKNS0_7field_tIS4_EESA_bm
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2ERKNS0_7field_tIS4_EESA_bm
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2ERKNS0_7field_tIS6_EESC_bm
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2ERKNS0_7field_tIS6_EESB_bm
152
153
template <typename Builder, typename T>
154
bigfield<Builder, T>::bigfield(const bigfield& other)
155
    : context(other.context)
156
    , binary_basis_limbs{ other.binary_basis_limbs[0],
157
                          other.binary_basis_limbs[1],
158
                          other.binary_basis_limbs[2],
159
                          other.binary_basis_limbs[3] }
160
    , prime_basis_limb(other.prime_basis_limb)
161
23.9M
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2ERKS6_
Line
Count
Source
161
21.9M
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2ERKS6_
Line
Count
Source
161
3.42k
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2ERKS8_
Line
Count
Source
161
110
{}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2ERKS7_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2ERKS7_
Line
Count
Source
161
79.2k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2ERKS7_
Line
Count
Source
161
520
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2ERKS9_
Line
Count
Source
161
1.75M
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2ERKS9_
Line
Count
Source
161
9.50k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2ERKS7_
Line
Count
Source
161
152k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2ERKS7_
Line
Count
Source
161
335
{}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2ERKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2ERKS9_
162
163
template <typename Builder, typename T>
164
bigfield<Builder, T>::bigfield(bigfield&& other)
165
    : context(other.context)
166
    , binary_basis_limbs{ other.binary_basis_limbs[0],
167
                          other.binary_basis_limbs[1],
168
                          other.binary_basis_limbs[2],
169
                          other.binary_basis_limbs[3] }
170
    , prime_basis_limb(other.prime_basis_limb)
171
1.22M
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2EOS6_
Line
Count
Source
171
1.12M
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2EOS6_
Line
Count
Source
171
788
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2EOS8_
Line
Count
Source
171
20
{}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2EOS7_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2EOS7_
Line
Count
Source
171
3.56k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2EOS7_
Line
Count
Source
171
123
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2EOS9_
Line
Count
Source
171
77.7k
{}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2EOS9_
Line
Count
Source
171
2.59k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2EOS7_
Line
Count
Source
171
11.3k
{}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2EOS7_
Line
Count
Source
171
50
{}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2EOS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2EOS9_
172
173
/**
174
 * @brief Creates a bigfield element from a uint512_t.
175
 * Bigfield element is constructed as a witness and not a circuit constant
176
 *
177
 * @param ctx
178
 * @param value
179
 * @param can_overflow Can the input value have more than log2(modulus) bits?
180
 * @param maximum_bitlength Provide the explicit maximum bitlength if known. Otherwise bigfield max value will be
181
 * either log2(modulus) bits iff can_overflow = false, or (4 * NUM_LIMB_BITS) iff can_overflow = true
182
 * @return bigfield<Builder, T>
183
 *
184
 * @details This method is 1 gate more efficient than constructing from 2 field_ct elements.
185
 */
186
template <typename Builder, typename T>
187
bigfield<Builder, T> bigfield<Builder, T>::create_from_u512_as_witness(Builder* ctx,
188
                                                                       const uint512_t& value,
189
                                                                       const bool can_overflow,
190
                                                                       const size_t maximum_bitlength)
191
2.41M
{
192
2.41M
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
2.41M
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
0
    std::array<uint256_t, 4> limbs;
195
0
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
0
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
0
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
0
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
2.41M
    if constexpr (HasPlookup<Builder>) {
201
2.41M
        field_t<Builder> limb_0(ctx);
202
2.41M
        field_t<Builder> limb_1(ctx);
203
2.41M
        field_t<Builder> limb_2(ctx);
204
2.41M
        field_t<Builder> limb_3(ctx);
205
2.41M
        field_t<Builder> prime_limb(ctx);
206
2.41M
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
2.41M
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
2.41M
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
2.41M
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
2.41M
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
2.41M
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
2.41M
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
2.41M
                                   limb_2.get_normalized_witness_index(),
215
2.41M
                                   limb_3.get_normalized_witness_index(),
216
2.41M
                                   prime_limb.get_normalized_witness_index(),
217
2.41M
                                   shift_1,
218
2.41M
                                   shift_2,
219
2.41M
                                   shift_3,
220
2.41M
                                   -1,
221
2.41M
                                   0 },
222
2.41M
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
2.41M
        ctx->create_dummy_gate(
226
2.41M
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
2.41M
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
2.41M
        bigfield result(ctx);
231
2.41M
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
2.41M
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
2.41M
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
2.41M
        result.binary_basis_limbs[3] =
235
2.41M
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
2.41M
        if (maximum_bitlength > 0) {
239
1.20M
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
0
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
0
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
0
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
0
        }
244
0
        result.prime_basis_limb = prime_limb;
245
0
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
0
                                       limb_1.get_normalized_witness_index(),
247
0
                                       (size_t)NUM_LIMB_BITS,
248
0
                                       (size_t)NUM_LIMB_BITS);
249
0
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
0
                                       limb_3.get_normalized_witness_index(),
251
0
                                       (size_t)NUM_LIMB_BITS,
252
0
                                       (size_t)num_last_limb_bits);
253
254
0
        return result;
255
2.41M
    } else {
256
0
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
0
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
0
                        can_overflow,
259
0
                        maximum_bitlength);
260
0
    }
261
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS8_9uint256_tEEEbm
Line
Count
Source
191
2.21M
{
192
2.21M
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
2.21M
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
2.21M
    std::array<uint256_t, 4> limbs;
195
2.21M
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
2.21M
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
2.21M
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
2.21M
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
2.21M
    if constexpr (HasPlookup<Builder>) {
201
2.21M
        field_t<Builder> limb_0(ctx);
202
2.21M
        field_t<Builder> limb_1(ctx);
203
2.21M
        field_t<Builder> limb_2(ctx);
204
2.21M
        field_t<Builder> limb_3(ctx);
205
2.21M
        field_t<Builder> prime_limb(ctx);
206
2.21M
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
2.21M
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
2.21M
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
2.21M
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
2.21M
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
2.21M
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
2.21M
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
2.21M
                                   limb_2.get_normalized_witness_index(),
215
2.21M
                                   limb_3.get_normalized_witness_index(),
216
2.21M
                                   prime_limb.get_normalized_witness_index(),
217
2.21M
                                   shift_1,
218
2.21M
                                   shift_2,
219
2.21M
                                   shift_3,
220
2.21M
                                   -1,
221
2.21M
                                   0 },
222
2.21M
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
2.21M
        ctx->create_dummy_gate(
226
2.21M
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
2.21M
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
2.21M
        bigfield result(ctx);
231
2.21M
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
2.21M
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
2.21M
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
2.21M
        result.binary_basis_limbs[3] =
235
2.21M
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
2.21M
        if (maximum_bitlength > 0) {
239
1.10M
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
1.10M
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
1.10M
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
1.10M
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
1.10M
        }
244
2.21M
        result.prime_basis_limb = prime_limb;
245
2.21M
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
2.21M
                                       limb_1.get_normalized_witness_index(),
247
2.21M
                                       (size_t)NUM_LIMB_BITS,
248
2.21M
                                       (size_t)NUM_LIMB_BITS);
249
2.21M
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
2.21M
                                       limb_3.get_normalized_witness_index(),
251
2.21M
                                       (size_t)NUM_LIMB_BITS,
252
2.21M
                                       (size_t)num_last_limb_bits);
253
254
2.21M
        return result;
255
2.21M
    } else {
256
2.21M
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
2.21M
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
2.21M
                        can_overflow,
259
2.21M
                        maximum_bitlength);
260
2.21M
    }
261
2.21M
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS8_9uint256_tEEEbm
Line
Count
Source
191
76
{
192
76
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
76
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
76
    std::array<uint256_t, 4> limbs;
195
76
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
76
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
76
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
76
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
76
    if constexpr (HasPlookup<Builder>) {
201
76
        field_t<Builder> limb_0(ctx);
202
76
        field_t<Builder> limb_1(ctx);
203
76
        field_t<Builder> limb_2(ctx);
204
76
        field_t<Builder> limb_3(ctx);
205
76
        field_t<Builder> prime_limb(ctx);
206
76
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
76
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
76
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
76
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
76
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
76
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
76
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
76
                                   limb_2.get_normalized_witness_index(),
215
76
                                   limb_3.get_normalized_witness_index(),
216
76
                                   prime_limb.get_normalized_witness_index(),
217
76
                                   shift_1,
218
76
                                   shift_2,
219
76
                                   shift_3,
220
76
                                   -1,
221
76
                                   0 },
222
76
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
76
        ctx->create_dummy_gate(
226
76
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
76
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
76
        bigfield result(ctx);
231
76
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
76
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
76
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
76
        result.binary_basis_limbs[3] =
235
76
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
76
        if (maximum_bitlength > 0) {
239
38
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
38
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
38
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
38
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
38
        }
244
76
        result.prime_basis_limb = prime_limb;
245
76
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
76
                                       limb_1.get_normalized_witness_index(),
247
76
                                       (size_t)NUM_LIMB_BITS,
248
76
                                       (size_t)NUM_LIMB_BITS);
249
76
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
76
                                       limb_3.get_normalized_witness_index(),
251
76
                                       (size_t)NUM_LIMB_BITS,
252
76
                                       (size_t)num_last_limb_bits);
253
254
76
        return result;
255
76
    } else {
256
76
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
76
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
76
                        can_overflow,
259
76
                        maximum_bitlength);
260
76
    }
261
76
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSA_9uint256_tEEEbm
Line
Count
Source
191
32
{
192
32
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
32
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
32
    std::array<uint256_t, 4> limbs;
195
32
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
32
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
32
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
32
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
32
    if constexpr (HasPlookup<Builder>) {
201
32
        field_t<Builder> limb_0(ctx);
202
32
        field_t<Builder> limb_1(ctx);
203
32
        field_t<Builder> limb_2(ctx);
204
32
        field_t<Builder> limb_3(ctx);
205
32
        field_t<Builder> prime_limb(ctx);
206
32
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
32
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
32
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
32
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
32
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
32
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
32
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
32
                                   limb_2.get_normalized_witness_index(),
215
32
                                   limb_3.get_normalized_witness_index(),
216
32
                                   prime_limb.get_normalized_witness_index(),
217
32
                                   shift_1,
218
32
                                   shift_2,
219
32
                                   shift_3,
220
32
                                   -1,
221
32
                                   0 },
222
32
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
32
        ctx->create_dummy_gate(
226
32
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
32
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
32
        bigfield result(ctx);
231
32
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
32
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
32
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
32
        result.binary_basis_limbs[3] =
235
32
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
32
        if (maximum_bitlength > 0) {
239
16
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
16
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
16
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
16
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
16
        }
244
32
        result.prime_basis_limb = prime_limb;
245
32
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
32
                                       limb_1.get_normalized_witness_index(),
247
32
                                       (size_t)NUM_LIMB_BITS,
248
32
                                       (size_t)NUM_LIMB_BITS);
249
32
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
32
                                       limb_3.get_normalized_witness_index(),
251
32
                                       (size_t)NUM_LIMB_BITS,
252
32
                                       (size_t)num_last_limb_bits);
253
254
32
        return result;
255
32
    } else {
256
32
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
32
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
32
                        can_overflow,
259
32
                        maximum_bitlength);
260
32
    }
261
32
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINS9_9uint256_tEEEbm
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS9_9uint256_tEEEbm
Line
Count
Source
191
8.01k
{
192
8.01k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
8.01k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
8.01k
    std::array<uint256_t, 4> limbs;
195
8.01k
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
8.01k
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
8.01k
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
8.01k
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
8.01k
    if constexpr (HasPlookup<Builder>) {
201
8.01k
        field_t<Builder> limb_0(ctx);
202
8.01k
        field_t<Builder> limb_1(ctx);
203
8.01k
        field_t<Builder> limb_2(ctx);
204
8.01k
        field_t<Builder> limb_3(ctx);
205
8.01k
        field_t<Builder> prime_limb(ctx);
206
8.01k
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
8.01k
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
8.01k
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
8.01k
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
8.01k
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
8.01k
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
8.01k
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
8.01k
                                   limb_2.get_normalized_witness_index(),
215
8.01k
                                   limb_3.get_normalized_witness_index(),
216
8.01k
                                   prime_limb.get_normalized_witness_index(),
217
8.01k
                                   shift_1,
218
8.01k
                                   shift_2,
219
8.01k
                                   shift_3,
220
8.01k
                                   -1,
221
8.01k
                                   0 },
222
8.01k
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
8.01k
        ctx->create_dummy_gate(
226
8.01k
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
8.01k
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
8.01k
        bigfield result(ctx);
231
8.01k
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
8.01k
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
8.01k
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
8.01k
        result.binary_basis_limbs[3] =
235
8.01k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
8.01k
        if (maximum_bitlength > 0) {
239
4.01k
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
4.01k
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
4.01k
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
4.01k
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
4.01k
        }
244
8.01k
        result.prime_basis_limb = prime_limb;
245
8.01k
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
8.01k
                                       limb_1.get_normalized_witness_index(),
247
8.01k
                                       (size_t)NUM_LIMB_BITS,
248
8.01k
                                       (size_t)NUM_LIMB_BITS);
249
8.01k
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
8.01k
                                       limb_3.get_normalized_witness_index(),
251
8.01k
                                       (size_t)NUM_LIMB_BITS,
252
8.01k
                                       (size_t)num_last_limb_bits);
253
254
8.01k
        return result;
255
8.01k
    } else {
256
8.01k
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
8.01k
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
8.01k
                        can_overflow,
259
8.01k
                        maximum_bitlength);
260
8.01k
    }
261
8.01k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS9_9uint256_tEEEbm
Line
Count
Source
191
54
{
192
54
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
54
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
54
    std::array<uint256_t, 4> limbs;
195
54
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
54
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
54
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
54
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
54
    if constexpr (HasPlookup<Builder>) {
201
54
        field_t<Builder> limb_0(ctx);
202
54
        field_t<Builder> limb_1(ctx);
203
54
        field_t<Builder> limb_2(ctx);
204
54
        field_t<Builder> limb_3(ctx);
205
54
        field_t<Builder> prime_limb(ctx);
206
54
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
54
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
54
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
54
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
54
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
54
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
54
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
54
                                   limb_2.get_normalized_witness_index(),
215
54
                                   limb_3.get_normalized_witness_index(),
216
54
                                   prime_limb.get_normalized_witness_index(),
217
54
                                   shift_1,
218
54
                                   shift_2,
219
54
                                   shift_3,
220
54
                                   -1,
221
54
                                   0 },
222
54
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
54
        ctx->create_dummy_gate(
226
54
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
54
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
54
        bigfield result(ctx);
231
54
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
54
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
54
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
54
        result.binary_basis_limbs[3] =
235
54
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
54
        if (maximum_bitlength > 0) {
239
27
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
27
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
27
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
27
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
27
        }
244
54
        result.prime_basis_limb = prime_limb;
245
54
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
54
                                       limb_1.get_normalized_witness_index(),
247
54
                                       (size_t)NUM_LIMB_BITS,
248
54
                                       (size_t)NUM_LIMB_BITS);
249
54
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
54
                                       limb_3.get_normalized_witness_index(),
251
54
                                       (size_t)NUM_LIMB_BITS,
252
54
                                       (size_t)num_last_limb_bits);
253
254
54
        return result;
255
54
    } else {
256
54
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
54
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
54
                        can_overflow,
259
54
                        maximum_bitlength);
260
54
    }
261
54
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSB_9uint256_tEEEbm
Line
Count
Source
191
172k
{
192
172k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
172k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
172k
    std::array<uint256_t, 4> limbs;
195
172k
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
172k
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
172k
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
172k
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
172k
    if constexpr (HasPlookup<Builder>) {
201
172k
        field_t<Builder> limb_0(ctx);
202
172k
        field_t<Builder> limb_1(ctx);
203
172k
        field_t<Builder> limb_2(ctx);
204
172k
        field_t<Builder> limb_3(ctx);
205
172k
        field_t<Builder> prime_limb(ctx);
206
172k
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
172k
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
172k
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
172k
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
172k
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
172k
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
172k
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
172k
                                   limb_2.get_normalized_witness_index(),
215
172k
                                   limb_3.get_normalized_witness_index(),
216
172k
                                   prime_limb.get_normalized_witness_index(),
217
172k
                                   shift_1,
218
172k
                                   shift_2,
219
172k
                                   shift_3,
220
172k
                                   -1,
221
172k
                                   0 },
222
172k
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
172k
        ctx->create_dummy_gate(
226
172k
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
172k
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
172k
        bigfield result(ctx);
231
172k
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
172k
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
172k
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
172k
        result.binary_basis_limbs[3] =
235
172k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
172k
        if (maximum_bitlength > 0) {
239
86.4k
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
86.4k
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
86.4k
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
86.4k
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
86.4k
        }
244
172k
        result.prime_basis_limb = prime_limb;
245
172k
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
172k
                                       limb_1.get_normalized_witness_index(),
247
172k
                                       (size_t)NUM_LIMB_BITS,
248
172k
                                       (size_t)NUM_LIMB_BITS);
249
172k
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
172k
                                       limb_3.get_normalized_witness_index(),
251
172k
                                       (size_t)NUM_LIMB_BITS,
252
172k
                                       (size_t)num_last_limb_bits);
253
254
172k
        return result;
255
172k
    } else {
256
172k
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
172k
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
172k
                        can_overflow,
259
172k
                        maximum_bitlength);
260
172k
    }
261
172k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSB_9uint256_tEEEbm
Line
Count
Source
191
1.15k
{
192
1.15k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
1.15k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
1.15k
    std::array<uint256_t, 4> limbs;
195
1.15k
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
1.15k
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
1.15k
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
1.15k
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
1.15k
    if constexpr (HasPlookup<Builder>) {
201
1.15k
        field_t<Builder> limb_0(ctx);
202
1.15k
        field_t<Builder> limb_1(ctx);
203
1.15k
        field_t<Builder> limb_2(ctx);
204
1.15k
        field_t<Builder> limb_3(ctx);
205
1.15k
        field_t<Builder> prime_limb(ctx);
206
1.15k
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
1.15k
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
1.15k
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
1.15k
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
1.15k
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
1.15k
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
1.15k
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
1.15k
                                   limb_2.get_normalized_witness_index(),
215
1.15k
                                   limb_3.get_normalized_witness_index(),
216
1.15k
                                   prime_limb.get_normalized_witness_index(),
217
1.15k
                                   shift_1,
218
1.15k
                                   shift_2,
219
1.15k
                                   shift_3,
220
1.15k
                                   -1,
221
1.15k
                                   0 },
222
1.15k
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
1.15k
        ctx->create_dummy_gate(
226
1.15k
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
1.15k
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
1.15k
        bigfield result(ctx);
231
1.15k
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
1.15k
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
1.15k
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
1.15k
        result.binary_basis_limbs[3] =
235
1.15k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
1.15k
        if (maximum_bitlength > 0) {
239
576
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
576
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
576
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
576
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
576
        }
244
1.15k
        result.prime_basis_limb = prime_limb;
245
1.15k
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
1.15k
                                       limb_1.get_normalized_witness_index(),
247
1.15k
                                       (size_t)NUM_LIMB_BITS,
248
1.15k
                                       (size_t)NUM_LIMB_BITS);
249
1.15k
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
1.15k
                                       limb_3.get_normalized_witness_index(),
251
1.15k
                                       (size_t)NUM_LIMB_BITS,
252
1.15k
                                       (size_t)num_last_limb_bits);
253
254
1.15k
        return result;
255
1.15k
    } else {
256
1.15k
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
1.15k
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
1.15k
                        can_overflow,
259
1.15k
                        maximum_bitlength);
260
1.15k
    }
261
1.15k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS9_9uint256_tEEEbm
Line
Count
Source
191
11.1k
{
192
11.1k
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
11.1k
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
11.1k
    std::array<uint256_t, 4> limbs;
195
11.1k
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
11.1k
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
11.1k
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
11.1k
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
11.1k
    if constexpr (HasPlookup<Builder>) {
201
11.1k
        field_t<Builder> limb_0(ctx);
202
11.1k
        field_t<Builder> limb_1(ctx);
203
11.1k
        field_t<Builder> limb_2(ctx);
204
11.1k
        field_t<Builder> limb_3(ctx);
205
11.1k
        field_t<Builder> prime_limb(ctx);
206
11.1k
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
11.1k
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
11.1k
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
11.1k
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
11.1k
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
11.1k
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
11.1k
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
11.1k
                                   limb_2.get_normalized_witness_index(),
215
11.1k
                                   limb_3.get_normalized_witness_index(),
216
11.1k
                                   prime_limb.get_normalized_witness_index(),
217
11.1k
                                   shift_1,
218
11.1k
                                   shift_2,
219
11.1k
                                   shift_3,
220
11.1k
                                   -1,
221
11.1k
                                   0 },
222
11.1k
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
11.1k
        ctx->create_dummy_gate(
226
11.1k
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
11.1k
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
11.1k
        bigfield result(ctx);
231
11.1k
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
11.1k
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
11.1k
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
11.1k
        result.binary_basis_limbs[3] =
235
11.1k
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
11.1k
        if (maximum_bitlength > 0) {
239
5.56k
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
5.56k
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
5.56k
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
5.56k
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
5.56k
        }
244
11.1k
        result.prime_basis_limb = prime_limb;
245
11.1k
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
11.1k
                                       limb_1.get_normalized_witness_index(),
247
11.1k
                                       (size_t)NUM_LIMB_BITS,
248
11.1k
                                       (size_t)NUM_LIMB_BITS);
249
11.1k
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
11.1k
                                       limb_3.get_normalized_witness_index(),
251
11.1k
                                       (size_t)NUM_LIMB_BITS,
252
11.1k
                                       (size_t)num_last_limb_bits);
253
254
11.1k
        return result;
255
11.1k
    } else {
256
11.1k
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
11.1k
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
11.1k
                        can_overflow,
259
11.1k
                        maximum_bitlength);
260
11.1k
    }
261
11.1k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS9_9uint256_tEEEbm
Line
Count
Source
191
20
{
192
20
    ASSERT((can_overflow == true && maximum_bitlength == 0) ||
193
20
           (can_overflow == false && (maximum_bitlength == 0 || maximum_bitlength > (3 * NUM_LIMB_BITS))));
194
20
    std::array<uint256_t, 4> limbs;
195
20
    limbs[0] = value.slice(0, NUM_LIMB_BITS).lo;
196
20
    limbs[1] = value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo;
197
20
    limbs[2] = value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo;
198
20
    limbs[3] = value.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo;
199
200
20
    if constexpr (HasPlookup<Builder>) {
201
20
        field_t<Builder> limb_0(ctx);
202
20
        field_t<Builder> limb_1(ctx);
203
20
        field_t<Builder> limb_2(ctx);
204
20
        field_t<Builder> limb_3(ctx);
205
20
        field_t<Builder> prime_limb(ctx);
206
20
        limb_0.witness_index = ctx->add_variable(bb::fr(limbs[0]));
207
20
        limb_1.witness_index = ctx->add_variable(bb::fr(limbs[1]));
208
20
        limb_2.witness_index = ctx->add_variable(bb::fr(limbs[2]));
209
20
        limb_3.witness_index = ctx->add_variable(bb::fr(limbs[3]));
210
20
        prime_limb.witness_index = ctx->add_variable(limb_0.get_value() + limb_1.get_value() * shift_1 +
211
20
                                                     limb_2.get_value() * shift_2 + limb_3.get_value() * shift_3);
212
        // evaluate prime basis limb with addition gate that taps into the 4th wire in the next gate
213
20
        ctx->create_big_add_gate({ limb_1.get_normalized_witness_index(),
214
20
                                   limb_2.get_normalized_witness_index(),
215
20
                                   limb_3.get_normalized_witness_index(),
216
20
                                   prime_limb.get_normalized_witness_index(),
217
20
                                   shift_1,
218
20
                                   shift_2,
219
20
                                   shift_3,
220
20
                                   -1,
221
20
                                   0 },
222
20
                                 true);
223
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add
224
        // gate
225
20
        ctx->create_dummy_gate(
226
20
            ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.get_normalized_witness_index());
227
228
20
        uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS;
229
230
20
        bigfield result(ctx);
231
20
        result.binary_basis_limbs[0] = Limb(limb_0, DEFAULT_MAXIMUM_LIMB);
232
20
        result.binary_basis_limbs[1] = Limb(limb_1, DEFAULT_MAXIMUM_LIMB);
233
20
        result.binary_basis_limbs[2] = Limb(limb_2, DEFAULT_MAXIMUM_LIMB);
234
20
        result.binary_basis_limbs[3] =
235
20
            Limb(limb_3, can_overflow ? DEFAULT_MAXIMUM_LIMB : DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB);
236
237
        // if maximum_bitlength is set, this supercedes can_overflow
238
20
        if (maximum_bitlength > 0) {
239
10
            ASSERT(maximum_bitlength > 3 * NUM_LIMB_BITS);
240
10
            num_last_limb_bits = maximum_bitlength - (3 * NUM_LIMB_BITS);
241
10
            uint256_t max_limb_value = (uint256_t(1) << num_last_limb_bits) - 1;
242
10
            result.binary_basis_limbs[3].maximum_value = max_limb_value;
243
10
        }
244
20
        result.prime_basis_limb = prime_limb;
245
20
        ctx->range_constrain_two_limbs(limb_0.get_normalized_witness_index(),
246
20
                                       limb_1.get_normalized_witness_index(),
247
20
                                       (size_t)NUM_LIMB_BITS,
248
20
                                       (size_t)NUM_LIMB_BITS);
249
20
        ctx->range_constrain_two_limbs(limb_2.get_normalized_witness_index(),
250
20
                                       limb_3.get_normalized_witness_index(),
251
20
                                       (size_t)NUM_LIMB_BITS,
252
20
                                       (size_t)num_last_limb_bits);
253
254
20
        return result;
255
20
    } else {
256
20
        return bigfield(witness_t(ctx, fr(limbs[0] + limbs[1] * shift_1)),
257
20
                        witness_t(ctx, fr(limbs[2] + limbs[3] * shift_1)),
258
20
                        can_overflow,
259
20
                        maximum_bitlength);
260
20
    }
261
20
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSB_9uint256_tEEEbm
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSB_9uint256_tEEEbm
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS8_9uint256_tEEEbm
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE27create_from_u512_as_witnessEPS4_RKNS_7numeric5uintxINS8_9uint256_tEEEbm
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINSA_9uint256_tEEEbm
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E27create_from_u512_as_witnessEPS6_RKNS_7numeric5uintxINS9_9uint256_tEEEbm
262
263
template <typename Builder, typename T> bigfield<Builder, T>::bigfield(const byte_array<Builder>& bytes)
264
520
{
265
520
    ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer
266
1.04k
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
1.04k
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
1.04k
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
1.04k
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
1.04k
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
1.04k
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
1.04k
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
1.04k
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
1.04k
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
1.04k
        sum.assert_equal(split_byte);
278
1.04k
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
1.04k
                                                                  (field_t<Builder>)hi_nibble);
280
1.04k
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESB_SF_
Line
Count
Source
266
62
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
62
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
62
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
62
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
62
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
62
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
62
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
62
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
62
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
62
        sum.assert_equal(split_byte);
278
62
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
62
                                                                  (field_t<Builder>)hi_nibble);
280
62
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESB_SF_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESD_SH_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESC_SG_
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESC_SG_
Line
Count
Source
266
20
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
20
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
20
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
20
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
20
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
20
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
20
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
20
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
20
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
20
        sum.assert_equal(split_byte);
278
20
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
20
                                                                  (field_t<Builder>)hi_nibble);
280
20
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESC_SG_
Line
Count
Source
266
48
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
48
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
48
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
48
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
48
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
48
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
48
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
48
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
48
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
48
        sum.assert_equal(split_byte);
278
48
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
48
                                                                  (field_t<Builder>)hi_nibble);
280
48
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESE_SI_
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESE_SI_
Line
Count
Source
266
864
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
864
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
864
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
864
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
864
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
864
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
864
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
864
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
864
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
864
        sum.assert_equal(split_byte);
278
864
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
864
                                                                  (field_t<Builder>)hi_nibble);
280
864
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESC_SG_
Line
Count
Source
266
16
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
16
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
16
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
16
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
16
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
16
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
16
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
16
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
16
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
16
        sum.assert_equal(split_byte);
278
16
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
16
                                                                  (field_t<Builder>)hi_nibble);
280
16
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EEE_clESC_SG_
Line
Count
Source
266
30
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
30
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
30
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
30
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
30
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
30
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
30
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
30
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
30
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
30
        sum.assert_equal(split_byte);
278
30
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
30
                                                                  (field_t<Builder>)hi_nibble);
280
30
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESE_SI_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EEE_clESE_SI_
281
282
0
    const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx,
283
0
                                                                  const field_t<Builder>& hi_bytes,
284
0
                                                                  const field_t<Builder>& lo_bytes,
285
1.04k
                                                                  const field_t<Builder>& split_byte) {
286
1.04k
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
1.04k
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
1.04k
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
1.04k
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
1.04k
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESF_SF_E_clESB_SF_SF_SF_
Line
Count
Source
285
62
                                                                  const field_t<Builder>& split_byte) {
286
62
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
62
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
62
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
62
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
62
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESF_SF_E_clESB_SF_SF_SF_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESH_SH_E_clESD_SH_SH_SH_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESG_SG_E_clESC_SG_SG_SG_
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESG_SG_E_clESC_SG_SG_SG_
Line
Count
Source
285
20
                                                                  const field_t<Builder>& split_byte) {
286
20
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
20
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
20
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
20
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
20
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESG_SG_E_clESC_SG_SG_SG_
Line
Count
Source
285
48
                                                                  const field_t<Builder>& split_byte) {
286
48
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
48
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
48
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
48
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
48
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESI_SI_E_clESE_SI_SI_SI_
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESI_SI_E_clESE_SI_SI_SI_
Line
Count
Source
285
864
                                                                  const field_t<Builder>& split_byte) {
286
864
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
864
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
864
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
864
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
864
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESG_SG_E_clESC_SG_SG_SG_
Line
Count
Source
285
16
                                                                  const field_t<Builder>& split_byte) {
286
16
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
16
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
16
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
16
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
16
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC1ERKNS0_10byte_arrayIS4_EEENKUlPS4_RKNS0_7field_tIS4_EESG_SG_E_clESC_SG_SG_SG_
Line
Count
Source
285
30
                                                                  const field_t<Builder>& split_byte) {
286
30
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
30
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
30
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
30
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
30
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESI_SI_E_clESE_SI_SI_SI_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC1ERKNS0_10byte_arrayIS6_EEENKUlPS6_RKNS0_7field_tIS6_EESI_SI_E_clESE_SI_SI_SI_
292
0
    Builder* ctx = bytes.get_context();
293
294
0
    const field_t<Builder> hi_8_bytes(bytes.slice(0, 6));
295
0
    const field_t<Builder> mid_split_byte(bytes.slice(6, 1));
296
0
    const field_t<Builder> mid_8_bytes(bytes.slice(7, 8));
297
298
0
    const field_t<Builder> lo_8_bytes(bytes.slice(15, 8));
299
0
    const field_t<Builder> lo_split_byte(bytes.slice(23, 1));
300
0
    const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8));
301
302
0
    const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
303
0
    const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
304
305
0
    const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true);
306
307
0
    const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
308
0
    res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits);
309
0
    *this = res;
310
0
    set_origin_tag(bytes.get_origin_tag());
311
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2ERKNS0_10byte_arrayIS4_EE
Line
Count
Source
264
31
{
265
31
    ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer
266
31
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
31
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
31
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
31
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
31
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
31
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
31
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
31
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
31
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
31
        sum.assert_equal(split_byte);
278
31
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
31
                                                                  (field_t<Builder>)hi_nibble);
280
31
    };
281
282
31
    const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx,
283
31
                                                                  const field_t<Builder>& hi_bytes,
284
31
                                                                  const field_t<Builder>& lo_bytes,
285
31
                                                                  const field_t<Builder>& split_byte) {
286
31
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
31
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
31
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
31
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
31
    };
292
31
    Builder* ctx = bytes.get_context();
293
294
31
    const field_t<Builder> hi_8_bytes(bytes.slice(0, 6));
295
31
    const field_t<Builder> mid_split_byte(bytes.slice(6, 1));
296
31
    const field_t<Builder> mid_8_bytes(bytes.slice(7, 8));
297
298
31
    const field_t<Builder> lo_8_bytes(bytes.slice(15, 8));
299
31
    const field_t<Builder> lo_split_byte(bytes.slice(23, 1));
300
31
    const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8));
301
302
31
    const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
303
31
    const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
304
305
31
    const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true);
306
307
31
    const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
308
31
    res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits);
309
31
    *this = res;
310
31
    set_origin_tag(bytes.get_origin_tag());
311
31
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2ERKNS0_10byte_arrayIS4_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2ERKNS0_10byte_arrayIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2ERKNS0_10byte_arrayIS6_EE
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEC2ERKNS0_10byte_arrayIS4_EE
Line
Count
Source
264
10
{
265
10
    ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer
266
10
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
10
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
10
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
10
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
10
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
10
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
10
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
10
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
10
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
10
        sum.assert_equal(split_byte);
278
10
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
10
                                                                  (field_t<Builder>)hi_nibble);
280
10
    };
281
282
10
    const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx,
283
10
                                                                  const field_t<Builder>& hi_bytes,
284
10
                                                                  const field_t<Builder>& lo_bytes,
285
10
                                                                  const field_t<Builder>& split_byte) {
286
10
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
10
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
10
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
10
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
10
    };
292
10
    Builder* ctx = bytes.get_context();
293
294
10
    const field_t<Builder> hi_8_bytes(bytes.slice(0, 6));
295
10
    const field_t<Builder> mid_split_byte(bytes.slice(6, 1));
296
10
    const field_t<Builder> mid_8_bytes(bytes.slice(7, 8));
297
298
10
    const field_t<Builder> lo_8_bytes(bytes.slice(15, 8));
299
10
    const field_t<Builder> lo_split_byte(bytes.slice(23, 1));
300
10
    const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8));
301
302
10
    const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
303
10
    const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
304
305
10
    const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true);
306
307
10
    const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
308
10
    res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits);
309
10
    *this = res;
310
10
    set_origin_tag(bytes.get_origin_tag());
311
10
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEC2ERKNS0_10byte_arrayIS4_EE
Line
Count
Source
264
24
{
265
24
    ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer
266
24
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
24
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
24
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
24
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
24
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
24
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
24
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
24
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
24
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
24
        sum.assert_equal(split_byte);
278
24
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
24
                                                                  (field_t<Builder>)hi_nibble);
280
24
    };
281
282
24
    const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx,
283
24
                                                                  const field_t<Builder>& hi_bytes,
284
24
                                                                  const field_t<Builder>& lo_bytes,
285
24
                                                                  const field_t<Builder>& split_byte) {
286
24
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
24
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
24
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
24
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
24
    };
292
24
    Builder* ctx = bytes.get_context();
293
294
24
    const field_t<Builder> hi_8_bytes(bytes.slice(0, 6));
295
24
    const field_t<Builder> mid_split_byte(bytes.slice(6, 1));
296
24
    const field_t<Builder> mid_8_bytes(bytes.slice(7, 8));
297
298
24
    const field_t<Builder> lo_8_bytes(bytes.slice(15, 8));
299
24
    const field_t<Builder> lo_split_byte(bytes.slice(23, 1));
300
24
    const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8));
301
302
24
    const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
303
24
    const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
304
305
24
    const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true);
306
307
24
    const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
308
24
    res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits);
309
24
    *this = res;
310
24
    set_origin_tag(bytes.get_origin_tag());
311
24
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEC2ERKNS0_10byte_arrayIS6_EE
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEC2ERKNS0_10byte_arrayIS6_EE
Line
Count
Source
264
432
{
265
432
    ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer
266
432
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
432
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
432
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
432
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
432
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
432
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
432
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
432
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
432
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
432
        sum.assert_equal(split_byte);
278
432
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
432
                                                                  (field_t<Builder>)hi_nibble);
280
432
    };
281
282
432
    const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx,
283
432
                                                                  const field_t<Builder>& hi_bytes,
284
432
                                                                  const field_t<Builder>& lo_bytes,
285
432
                                                                  const field_t<Builder>& split_byte) {
286
432
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
432
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
432
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
432
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
432
    };
292
432
    Builder* ctx = bytes.get_context();
293
294
432
    const field_t<Builder> hi_8_bytes(bytes.slice(0, 6));
295
432
    const field_t<Builder> mid_split_byte(bytes.slice(6, 1));
296
432
    const field_t<Builder> mid_8_bytes(bytes.slice(7, 8));
297
298
432
    const field_t<Builder> lo_8_bytes(bytes.slice(15, 8));
299
432
    const field_t<Builder> lo_split_byte(bytes.slice(23, 1));
300
432
    const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8));
301
302
432
    const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
303
432
    const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
304
305
432
    const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true);
306
307
432
    const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
308
432
    res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits);
309
432
    *this = res;
310
432
    set_origin_tag(bytes.get_origin_tag());
311
432
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEC2ERKNS0_10byte_arrayIS4_EE
Line
Count
Source
264
8
{
265
8
    ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer
266
8
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
8
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
8
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
8
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
8
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
8
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
8
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
8
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
8
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
8
        sum.assert_equal(split_byte);
278
8
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
8
                                                                  (field_t<Builder>)hi_nibble);
280
8
    };
281
282
8
    const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx,
283
8
                                                                  const field_t<Builder>& hi_bytes,
284
8
                                                                  const field_t<Builder>& lo_bytes,
285
8
                                                                  const field_t<Builder>& split_byte) {
286
8
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
8
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
8
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
8
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
8
    };
292
8
    Builder* ctx = bytes.get_context();
293
294
8
    const field_t<Builder> hi_8_bytes(bytes.slice(0, 6));
295
8
    const field_t<Builder> mid_split_byte(bytes.slice(6, 1));
296
8
    const field_t<Builder> mid_8_bytes(bytes.slice(7, 8));
297
298
8
    const field_t<Builder> lo_8_bytes(bytes.slice(15, 8));
299
8
    const field_t<Builder> lo_split_byte(bytes.slice(23, 1));
300
8
    const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8));
301
302
8
    const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
303
8
    const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
304
305
8
    const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true);
306
307
8
    const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
308
8
    res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits);
309
8
    *this = res;
310
8
    set_origin_tag(bytes.get_origin_tag());
311
8
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEC2ERKNS0_10byte_arrayIS4_EE
Line
Count
Source
264
15
{
265
15
    ASSERT(bytes.size() == 32); // we treat input as a 256-bit big integer
266
15
    const auto split_byte_into_nibbles = [](Builder* ctx, const field_t<Builder>& split_byte) {
267
15
        const uint64_t byte_val = uint256_t(split_byte.get_value()).data[0];
268
15
        const uint64_t lo_nibble_val = byte_val & 15ULL;
269
15
        const uint64_t hi_nibble_val = byte_val >> 4;
270
271
15
        const field_t<Builder> lo_nibble(witness_t<Builder>(ctx, lo_nibble_val));
272
15
        const field_t<Builder> hi_nibble(witness_t<Builder>(ctx, hi_nibble_val));
273
15
        lo_nibble.create_range_constraint(4, "bigfield: lo_nibble too large");
274
15
        hi_nibble.create_range_constraint(4, "bigfield: hi_nibble too large");
275
276
15
        const field_t<Builder> sum = lo_nibble + (hi_nibble * 16);
277
15
        sum.assert_equal(split_byte);
278
15
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_nibble,
279
15
                                                                  (field_t<Builder>)hi_nibble);
280
15
    };
281
282
15
    const auto reconstruct_two_limbs = [&split_byte_into_nibbles](Builder* ctx,
283
15
                                                                  const field_t<Builder>& hi_bytes,
284
15
                                                                  const field_t<Builder>& lo_bytes,
285
15
                                                                  const field_t<Builder>& split_byte) {
286
15
        const auto [lo_nibble, hi_nibble] = split_byte_into_nibbles(ctx, split_byte);
287
288
15
        field_t<Builder> hi_limb = hi_nibble + hi_bytes * 16;
289
15
        field_t<Builder> lo_limb = lo_bytes + lo_nibble * field_t<Builder>(ctx, uint256_t(1) << 64);
290
15
        return std::make_pair<field_t<Builder>, field_t<Builder>>((field_t<Builder>)lo_limb, (field_t<Builder>)hi_limb);
291
15
    };
292
15
    Builder* ctx = bytes.get_context();
293
294
15
    const field_t<Builder> hi_8_bytes(bytes.slice(0, 6));
295
15
    const field_t<Builder> mid_split_byte(bytes.slice(6, 1));
296
15
    const field_t<Builder> mid_8_bytes(bytes.slice(7, 8));
297
298
15
    const field_t<Builder> lo_8_bytes(bytes.slice(15, 8));
299
15
    const field_t<Builder> lo_split_byte(bytes.slice(23, 1));
300
15
    const field_t<Builder> lolo_8_bytes(bytes.slice(24, 8));
301
302
15
    const auto [limb0, limb1] = reconstruct_two_limbs(ctx, lo_8_bytes, lolo_8_bytes, lo_split_byte);
303
15
    const auto [limb2, limb3] = reconstruct_two_limbs(ctx, hi_8_bytes, mid_8_bytes, mid_split_byte);
304
305
15
    const auto res = bigfield::unsafe_construct_from_limbs(limb0, limb1, limb2, limb3, true);
306
307
15
    const auto num_last_limb_bits = 256 - (NUM_LIMB_BITS * 3);
308
15
    res.binary_basis_limbs[3].maximum_value = (uint64_t(1) << num_last_limb_bits);
309
15
    *this = res;
310
15
    set_origin_tag(bytes.get_origin_tag());
311
15
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEC2ERKNS0_10byte_arrayIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEC2ERKNS0_10byte_arrayIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEC2ERKNS0_10byte_arrayIS4_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEC2ERKNS0_10byte_arrayIS4_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEC2ERKNS0_10byte_arrayIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EC2ERKNS0_10byte_arrayIS6_EE
312
313
template <typename Builder, typename T> bigfield<Builder, T>& bigfield<Builder, T>::operator=(const bigfield& other)
314
1.83M
{
315
1.83M
    context = other.context;
316
1.83M
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
1.83M
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
1.83M
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
1.83M
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
1.83M
    prime_basis_limb = other.prime_basis_limb;
321
1.83M
    return *this;
322
1.83M
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEaSERKS6_
Line
Count
Source
314
1.74M
{
315
1.74M
    context = other.context;
316
1.74M
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
1.74M
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
1.74M
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
1.74M
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
1.74M
    prime_basis_limb = other.prime_basis_limb;
321
1.74M
    return *this;
322
1.74M
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEaSERKS6_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEaSERKS8_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EaSERKS7_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEaSERKS7_
Line
Count
Source
314
3.64k
{
315
3.64k
    context = other.context;
316
3.64k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
3.64k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
3.64k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
3.64k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
3.64k
    prime_basis_limb = other.prime_basis_limb;
321
3.64k
    return *this;
322
3.64k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEaSERKS7_
Line
Count
Source
314
60
{
315
60
    context = other.context;
316
60
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
60
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
60
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
60
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
60
    prime_basis_limb = other.prime_basis_limb;
321
60
    return *this;
322
60
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEaSERKS9_
Line
Count
Source
314
80.9k
{
315
80.9k
    context = other.context;
316
80.9k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
80.9k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
80.9k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
80.9k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
80.9k
    prime_basis_limb = other.prime_basis_limb;
321
80.9k
    return *this;
322
80.9k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEaSERKS9_
Line
Count
Source
314
1.00k
{
315
1.00k
    context = other.context;
316
1.00k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
1.00k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
1.00k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
1.00k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
1.00k
    prime_basis_limb = other.prime_basis_limb;
321
1.00k
    return *this;
322
1.00k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEaSERKS7_
Line
Count
Source
314
5.54k
{
315
5.54k
    context = other.context;
316
5.54k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
5.54k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
5.54k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
5.54k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
5.54k
    prime_basis_limb = other.prime_basis_limb;
321
5.54k
    return *this;
322
5.54k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEaSERKS7_
Line
Count
Source
314
15
{
315
15
    context = other.context;
316
15
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
317
15
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
318
15
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
319
15
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
320
15
    prime_basis_limb = other.prime_basis_limb;
321
15
    return *this;
322
15
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEaSERKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEaSERKS9_
323
324
template <typename Builder, typename T> bigfield<Builder, T>& bigfield<Builder, T>::operator=(bigfield&& other)
325
4.23M
{
326
4.23M
    context = other.context;
327
4.23M
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
4.23M
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
4.23M
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
4.23M
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
4.23M
    prime_basis_limb = other.prime_basis_limb;
332
4.23M
    return *this;
333
4.23M
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEaSEOS6_
Line
Count
Source
325
3.97M
{
326
3.97M
    context = other.context;
327
3.97M
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
3.97M
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
3.97M
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
3.97M
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
3.97M
    prime_basis_limb = other.prime_basis_limb;
332
3.97M
    return *this;
333
3.97M
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEaSEOS6_
Line
Count
Source
325
1.13k
{
326
1.13k
    context = other.context;
327
1.13k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
1.13k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
1.13k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
1.13k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
1.13k
    prime_basis_limb = other.prime_basis_limb;
332
1.13k
    return *this;
333
1.13k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEaSEOS8_
Line
Count
Source
325
48
{
326
48
    context = other.context;
327
48
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
48
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
48
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
48
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
48
    prime_basis_limb = other.prime_basis_limb;
332
48
    return *this;
333
48
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EaSEOS7_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEaSEOS7_
Line
Count
Source
325
10.2k
{
326
10.2k
    context = other.context;
327
10.2k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
10.2k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
10.2k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
10.2k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
10.2k
    prime_basis_limb = other.prime_basis_limb;
332
10.2k
    return *this;
333
10.2k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEaSEOS7_
Line
Count
Source
325
126
{
326
126
    context = other.context;
327
126
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
126
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
126
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
126
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
126
    prime_basis_limb = other.prime_basis_limb;
332
126
    return *this;
333
126
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEaSEOS9_
Line
Count
Source
325
225k
{
326
225k
    context = other.context;
327
225k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
225k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
225k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
225k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
225k
    prime_basis_limb = other.prime_basis_limb;
332
225k
    return *this;
333
225k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEaSEOS9_
Line
Count
Source
325
2.59k
{
326
2.59k
    context = other.context;
327
2.59k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
2.59k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
2.59k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
2.59k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
2.59k
    prime_basis_limb = other.prime_basis_limb;
332
2.59k
    return *this;
333
2.59k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEaSEOS7_
Line
Count
Source
325
14.7k
{
326
14.7k
    context = other.context;
327
14.7k
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
14.7k
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
14.7k
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
14.7k
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
14.7k
    prime_basis_limb = other.prime_basis_limb;
332
14.7k
    return *this;
333
14.7k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEaSEOS7_
Line
Count
Source
325
70
{
326
70
    context = other.context;
327
70
    binary_basis_limbs[0] = other.binary_basis_limbs[0];
328
70
    binary_basis_limbs[1] = other.binary_basis_limbs[1];
329
70
    binary_basis_limbs[2] = other.binary_basis_limbs[2];
330
70
    binary_basis_limbs[3] = other.binary_basis_limbs[3];
331
70
    prime_basis_limb = other.prime_basis_limb;
332
70
    return *this;
333
70
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEaSEOS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEaSEOS9_
334
335
template <typename Builder, typename T> uint512_t bigfield<Builder, T>::get_value() const
336
8.12M
{
337
8.12M
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
8.12M
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
8.12M
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
8.12M
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
8.12M
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
8.12M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE9get_valueEv
Line
Count
Source
336
7.45M
{
337
7.45M
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
7.45M
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
7.45M
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
7.45M
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
7.45M
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
7.45M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE9get_valueEv
Line
Count
Source
336
847
{
337
847
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
847
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
847
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
847
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
847
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
847
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE9get_valueEv
Line
Count
Source
336
67
{
337
67
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
67
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
67
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
67
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
67
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
67
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E9get_valueEv
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE9get_valueEv
Line
Count
Source
336
27.1k
{
337
27.1k
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
27.1k
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
27.1k
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
27.1k
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
27.1k
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
27.1k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE9get_valueEv
Line
Count
Source
336
218
{
337
218
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
218
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
218
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
218
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
218
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
218
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE9get_valueEv
Line
Count
Source
336
590k
{
337
590k
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
590k
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
590k
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
590k
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
590k
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
590k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE9get_valueEv
Line
Count
Source
336
4.60k
{
337
4.60k
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
4.60k
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
4.60k
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
4.60k
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
4.60k
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
4.60k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE9get_valueEv
Line
Count
Source
336
48.4k
{
337
48.4k
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
48.4k
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
48.4k
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
48.4k
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
48.4k
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
48.4k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE9get_valueEv
Line
Count
Source
336
100
{
337
100
    uint512_t t0 = uint256_t(binary_basis_limbs[0].element.get_value());
338
100
    uint512_t t1 = uint256_t(binary_basis_limbs[1].element.get_value());
339
100
    uint512_t t2 = uint256_t(binary_basis_limbs[2].element.get_value());
340
100
    uint512_t t3 = uint256_t(binary_basis_limbs[3].element.get_value());
341
100
    return t0 + (t1 << (NUM_LIMB_BITS)) + (t2 << (2 * NUM_LIMB_BITS)) + (t3 << (3 * NUM_LIMB_BITS));
342
100
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE9get_valueEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE9get_valueEv
343
344
template <typename Builder, typename T> uint512_t bigfield<Builder, T>::get_maximum_value() const
345
16.7M
{
346
16.7M
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
16.7M
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
16.7M
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
16.7M
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
16.7M
    return t0 + t1 + t2 + t3;
351
16.7M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE17get_maximum_valueEv
Line
Count
Source
345
15.3M
{
346
15.3M
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
15.3M
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
15.3M
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
15.3M
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
15.3M
    return t0 + t1 + t2 + t3;
351
15.3M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE17get_maximum_valueEv
Line
Count
Source
345
1.49k
{
346
1.49k
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
1.49k
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
1.49k
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
1.49k
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
1.49k
    return t0 + t1 + t2 + t3;
351
1.49k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE17get_maximum_valueEv
Line
Count
Source
345
64
{
346
64
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
64
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
64
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
64
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
64
    return t0 + t1 + t2 + t3;
351
64
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E17get_maximum_valueEv
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE17get_maximum_valueEv
Line
Count
Source
345
55.1k
{
346
55.1k
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
55.1k
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
55.1k
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
55.1k
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
55.1k
    return t0 + t1 + t2 + t3;
351
55.1k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE17get_maximum_valueEv
Line
Count
Source
345
370
{
346
370
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
370
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
370
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
370
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
370
    return t0 + t1 + t2 + t3;
351
370
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE17get_maximum_valueEv
Line
Count
Source
345
1.22M
{
346
1.22M
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
1.22M
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
1.22M
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
1.22M
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
1.22M
    return t0 + t1 + t2 + t3;
351
1.22M
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE17get_maximum_valueEv
Line
Count
Source
345
7.48k
{
346
7.48k
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
7.48k
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
7.48k
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
7.48k
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
7.48k
    return t0 + t1 + t2 + t3;
351
7.48k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE17get_maximum_valueEv
Line
Count
Source
345
94.9k
{
346
94.9k
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
94.9k
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
94.9k
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
94.9k
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
94.9k
    return t0 + t1 + t2 + t3;
351
94.9k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE17get_maximum_valueEv
Line
Count
Source
345
156
{
346
156
    uint512_t t0 = uint512_t(binary_basis_limbs[0].maximum_value);
347
156
    uint512_t t1 = uint512_t(binary_basis_limbs[1].maximum_value) << NUM_LIMB_BITS;
348
156
    uint512_t t2 = uint512_t(binary_basis_limbs[2].maximum_value) << (NUM_LIMB_BITS * 2);
349
156
    uint512_t t3 = uint512_t(binary_basis_limbs[3].maximum_value) << (NUM_LIMB_BITS * 3);
350
156
    return t0 + t1 + t2 + t3;
351
156
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE17get_maximum_valueEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE17get_maximum_valueEv
352
353
/**
354
 * @brief Add a field element to the lower limb. CAUTION (the element has to be constrained before using this
355
 * function)
356
 *
357
 * @details Sometimes we need to add a small constrained value to a bigfield element (for example, a boolean value),
358
 * but we don't want to construct a full bigfield element for that as it would take too many gates. If the maximum
359
 * value of the field element being added is small enough, we can simply add it to the lowest limb and increase its
360
 * maximum value. That will create 2 additional constraints instead of 5/3 needed to add 2 bigfield elements and
361
 * several needed to construct a bigfield element.
362
 *
363
 * @tparam Builder Builder
364
 * @tparam T Field Parameters
365
 * @param other Field element that will be added to the lower
366
 * @param other_maximum_value The maximum value of other
367
 * @return bigfield<Builder, T> Result
368
 */
369
template <typename Builder, typename T>
370
bigfield<Builder, T> bigfield<Builder, T>::add_to_lower_limb(const field_t<Builder>& other,
371
                                                             uint256_t other_maximum_value) const
372
1.20k
{
373
1.20k
    reduction_check();
374
1.20k
    ASSERT((uint512_t(other_maximum_value) + uint512_t(binary_basis_limbs[0].maximum_value)) <=
375
1.20k
           uint512_t(get_maximum_unreduced_limb_value()));
376
    // needed cause a constant doesn't have a valid context
377
1.20k
    Builder* ctx = context ? context : other.context;
378
379
1.20k
    if (is_constant() && other.is_constant()) {
380
0
        return bigfield(ctx, uint256_t((get_value() + uint256_t(other.get_value())) % modulus_u512));
381
0
    }
382
383
1.20k
    bigfield result;
384
    // If the original value is constant, we have to reinitialize the higher limbs to be witnesses when adding a witness
385
1.20k
    if (is_constant()) {
386
607
        auto context = other.context;
387
2.42k
        for (size_t i = 1; i < 4; i++) {
388
            // Construct a witness element from the original constant limb
389
1.82k
            result.binary_basis_limbs[i] =
390
1.82k
                Limb(field_t<Builder>::from_witness(context, binary_basis_limbs[i].element.get_value()),
391
1.82k
                     binary_basis_limbs[i].maximum_value);
392
            // Ensure it is fixed
393
1.82k
            result.binary_basis_limbs[i].element.fix_witness();
394
1.82k
            result.context = ctx;
395
1.82k
        }
396
607
    } else {
397
398
        // if this element is a witness, then all limbs will be witnesses
399
600
        result = *this;
400
600
    }
401
1.20k
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + other_maximum_value;
402
403
1.20k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other;
404
1.20k
    result.prime_basis_limb = prime_basis_limb + other;
405
1.20k
    result.set_origin_tag(OriginTag(get_origin_tag(), other.tag));
406
1.20k
    return result;
407
0
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE
Line
Count
Source
372
7
{
373
7
    reduction_check();
374
7
    ASSERT((uint512_t(other_maximum_value) + uint512_t(binary_basis_limbs[0].maximum_value)) <=
375
7
           uint512_t(get_maximum_unreduced_limb_value()));
376
    // needed cause a constant doesn't have a valid context
377
7
    Builder* ctx = context ? context : other.context;
378
379
7
    if (is_constant() && other.is_constant()) {
380
0
        return bigfield(ctx, uint256_t((get_value() + uint256_t(other.get_value())) % modulus_u512));
381
0
    }
382
383
7
    bigfield result;
384
    // If the original value is constant, we have to reinitialize the higher limbs to be witnesses when adding a witness
385
7
    if (is_constant()) {
386
7
        auto context = other.context;
387
28
        for (size_t i = 1; i < 4; i++) {
388
            // Construct a witness element from the original constant limb
389
21
            result.binary_basis_limbs[i] =
390
21
                Limb(field_t<Builder>::from_witness(context, binary_basis_limbs[i].element.get_value()),
391
21
                     binary_basis_limbs[i].maximum_value);
392
            // Ensure it is fixed
393
21
            result.binary_basis_limbs[i].element.fix_witness();
394
21
            result.context = ctx;
395
21
        }
396
7
    } else {
397
398
        // if this element is a witness, then all limbs will be witnesses
399
0
        result = *this;
400
0
    }
401
7
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + other_maximum_value;
402
403
7
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other;
404
7
    result.prime_basis_limb = prime_basis_limb + other;
405
7
    result.set_origin_tag(OriginTag(get_origin_tag(), other.tag));
406
7
    return result;
407
7
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE
Line
Count
Source
372
48
{
373
48
    reduction_check();
374
48
    ASSERT((uint512_t(other_maximum_value) + uint512_t(binary_basis_limbs[0].maximum_value)) <=
375
48
           uint512_t(get_maximum_unreduced_limb_value()));
376
    // needed cause a constant doesn't have a valid context
377
48
    Builder* ctx = context ? context : other.context;
378
379
48
    if (is_constant() && other.is_constant()) {
380
0
        return bigfield(ctx, uint256_t((get_value() + uint256_t(other.get_value())) % modulus_u512));
381
0
    }
382
383
48
    bigfield result;
384
    // If the original value is constant, we have to reinitialize the higher limbs to be witnesses when adding a witness
385
48
    if (is_constant()) {
386
24
        auto context = other.context;
387
96
        for (size_t i = 1; i < 4; i++) {
388
            // Construct a witness element from the original constant limb
389
72
            result.binary_basis_limbs[i] =
390
72
                Limb(field_t<Builder>::from_witness(context, binary_basis_limbs[i].element.get_value()),
391
72
                     binary_basis_limbs[i].maximum_value);
392
            // Ensure it is fixed
393
72
            result.binary_basis_limbs[i].element.fix_witness();
394
72
            result.context = ctx;
395
72
        }
396
24
    } else {
397
398
        // if this element is a witness, then all limbs will be witnesses
399
24
        result = *this;
400
24
    }
401
48
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + other_maximum_value;
402
403
48
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other;
404
48
    result.prime_basis_limb = prime_basis_limb + other;
405
48
    result.set_origin_tag(OriginTag(get_origin_tag(), other.tag));
406
48
    return result;
407
48
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE
Line
Count
Source
372
1.15k
{
373
1.15k
    reduction_check();
374
1.15k
    ASSERT((uint512_t(other_maximum_value) + uint512_t(binary_basis_limbs[0].maximum_value)) <=
375
1.15k
           uint512_t(get_maximum_unreduced_limb_value()));
376
    // needed cause a constant doesn't have a valid context
377
1.15k
    Builder* ctx = context ? context : other.context;
378
379
1.15k
    if (is_constant() && other.is_constant()) {
380
0
        return bigfield(ctx, uint256_t((get_value() + uint256_t(other.get_value())) % modulus_u512));
381
0
    }
382
383
1.15k
    bigfield result;
384
    // If the original value is constant, we have to reinitialize the higher limbs to be witnesses when adding a witness
385
1.15k
    if (is_constant()) {
386
576
        auto context = other.context;
387
2.30k
        for (size_t i = 1; i < 4; i++) {
388
            // Construct a witness element from the original constant limb
389
1.72k
            result.binary_basis_limbs[i] =
390
1.72k
                Limb(field_t<Builder>::from_witness(context, binary_basis_limbs[i].element.get_value()),
391
1.72k
                     binary_basis_limbs[i].maximum_value);
392
            // Ensure it is fixed
393
1.72k
            result.binary_basis_limbs[i].element.fix_witness();
394
1.72k
            result.context = ctx;
395
1.72k
        }
396
576
    } else {
397
398
        // if this element is a witness, then all limbs will be witnesses
399
576
        result = *this;
400
576
    }
401
1.15k
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + other_maximum_value;
402
403
1.15k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other;
404
1.15k
    result.prime_basis_limb = prime_basis_limb + other;
405
1.15k
    result.set_origin_tag(OriginTag(get_origin_tag(), other.tag));
406
1.15k
    return result;
407
1.15k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE17add_to_lower_limbERKNS0_7field_tIS4_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E17add_to_lower_limbERKNS0_7field_tIS6_EENS_7numeric9uint256_tE
408
409
template <typename Builder, typename T>
410
bigfield<Builder, T> bigfield<Builder, T>::operator+(const bigfield& other) const
411
182k
{
412
182k
    reduction_check();
413
182k
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
182k
    Builder* ctx = context ? context : other.context;
416
417
182k
    if (is_constant() && other.is_constant()) {
418
1.59k
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
1.59k
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
1.59k
        return result;
421
1.59k
    }
422
180k
    bigfield result(ctx);
423
180k
    result.binary_basis_limbs[0].maximum_value =
424
180k
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
180k
    result.binary_basis_limbs[1].maximum_value =
426
180k
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
180k
    result.binary_basis_limbs[2].maximum_value =
428
180k
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
180k
    result.binary_basis_limbs[3].maximum_value =
430
180k
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
180k
    if constexpr (HasPlookup<Builder>) {
433
180k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
180k
            !is_constant() && !other.is_constant()) {
435
143k
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
143k
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
143k
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
143k
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
143k
            limbconst = limbconst || prime_basis_limb.is_constant();
440
143k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
143k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
143k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
143k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
143k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
143k
            limbconst =
446
143k
                limbconst || (prime_basis_limb.get_witness_index() ==
447
143k
                              other.prime_basis_limb
448
143k
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
143k
            if (!limbconst) {
451
29.4k
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
29.4k
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
29.4k
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
29.4k
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
29.4k
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
29.4k
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
29.4k
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
29.4k
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
29.4k
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
29.4k
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
29.4k
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
29.4k
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
29.4k
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
29.4k
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
29.4k
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
29.4k
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
29.4k
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
29.4k
                          other.binary_basis_limbs[0].element.additive_constant);
469
29.4k
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
29.4k
                          other.binary_basis_limbs[1].element.additive_constant);
471
29.4k
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
29.4k
                          other.binary_basis_limbs[2].element.additive_constant);
473
29.4k
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
29.4k
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
29.4k
                uint32_t xp(prime_basis_limb.witness_index);
477
29.4k
                uint32_t yp(other.prime_basis_limb.witness_index);
478
29.4k
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
29.4k
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
29.4k
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
29.4k
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
29.4k
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
29.4k
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
29.4k
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
29.4k
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
29.4k
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
29.4k
                return result;
488
29.4k
            }
489
143k
        }
490
180k
    }
491
492
151k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
151k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
151k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
151k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
151k
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
151k
    return result;
498
180k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEplERKS6_
Line
Count
Source
411
145k
{
412
145k
    reduction_check();
413
145k
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
145k
    Builder* ctx = context ? context : other.context;
416
417
145k
    if (is_constant() && other.is_constant()) {
418
1.59k
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
1.59k
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
1.59k
        return result;
421
1.59k
    }
422
144k
    bigfield result(ctx);
423
144k
    result.binary_basis_limbs[0].maximum_value =
424
144k
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
144k
    result.binary_basis_limbs[1].maximum_value =
426
144k
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
144k
    result.binary_basis_limbs[2].maximum_value =
428
144k
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
144k
    result.binary_basis_limbs[3].maximum_value =
430
144k
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
144k
    if constexpr (HasPlookup<Builder>) {
433
144k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
144k
            !is_constant() && !other.is_constant()) {
435
113k
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
113k
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
113k
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
113k
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
113k
            limbconst = limbconst || prime_basis_limb.is_constant();
440
113k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
113k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
113k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
113k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
113k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
113k
            limbconst =
446
113k
                limbconst || (prime_basis_limb.get_witness_index() ==
447
113k
                              other.prime_basis_limb
448
113k
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
113k
            if (!limbconst) {
451
29.4k
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
29.4k
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
29.4k
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
29.4k
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
29.4k
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
29.4k
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
29.4k
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
29.4k
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
29.4k
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
29.4k
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
29.4k
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
29.4k
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
29.4k
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
29.4k
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
29.4k
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
29.4k
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
29.4k
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
29.4k
                          other.binary_basis_limbs[0].element.additive_constant);
469
29.4k
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
29.4k
                          other.binary_basis_limbs[1].element.additive_constant);
471
29.4k
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
29.4k
                          other.binary_basis_limbs[2].element.additive_constant);
473
29.4k
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
29.4k
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
29.4k
                uint32_t xp(prime_basis_limb.witness_index);
477
29.4k
                uint32_t yp(other.prime_basis_limb.witness_index);
478
29.4k
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
29.4k
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
29.4k
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
29.4k
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
29.4k
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
29.4k
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
29.4k
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
29.4k
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
29.4k
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
29.4k
                return result;
488
29.4k
            }
489
113k
        }
490
144k
    }
491
492
114k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
114k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
114k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
114k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
114k
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
114k
    return result;
498
144k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEplERKS6_
Line
Count
Source
411
39
{
412
39
    reduction_check();
413
39
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
39
    Builder* ctx = context ? context : other.context;
416
417
39
    if (is_constant() && other.is_constant()) {
418
0
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
0
        return result;
421
0
    }
422
39
    bigfield result(ctx);
423
39
    result.binary_basis_limbs[0].maximum_value =
424
39
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
39
    result.binary_basis_limbs[1].maximum_value =
426
39
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
39
    result.binary_basis_limbs[2].maximum_value =
428
39
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
39
    result.binary_basis_limbs[3].maximum_value =
430
39
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
39
    if constexpr (HasPlookup<Builder>) {
433
39
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
39
            !is_constant() && !other.is_constant()) {
435
30
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
30
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
30
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
30
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
30
            limbconst = limbconst || prime_basis_limb.is_constant();
440
30
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
30
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
30
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
30
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
30
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
30
            limbconst =
446
30
                limbconst || (prime_basis_limb.get_witness_index() ==
447
30
                              other.prime_basis_limb
448
30
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
30
            if (!limbconst) {
451
27
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
27
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
27
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
27
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
27
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
27
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
27
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
27
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
27
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
27
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
27
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
27
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
27
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
27
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
27
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
27
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
27
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
27
                          other.binary_basis_limbs[0].element.additive_constant);
469
27
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
27
                          other.binary_basis_limbs[1].element.additive_constant);
471
27
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
27
                          other.binary_basis_limbs[2].element.additive_constant);
473
27
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
27
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
27
                uint32_t xp(prime_basis_limb.witness_index);
477
27
                uint32_t yp(other.prime_basis_limb.witness_index);
478
27
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
27
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
27
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
27
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
27
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
27
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
27
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
27
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
27
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
27
                return result;
488
27
            }
489
30
        }
490
39
    }
491
492
12
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
12
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
12
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
12
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
12
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
12
    return result;
498
39
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEplERKS8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EplERKS7_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEplERKS7_
Line
Count
Source
411
1.73k
{
412
1.73k
    reduction_check();
413
1.73k
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
1.73k
    Builder* ctx = context ? context : other.context;
416
417
1.73k
    if (is_constant() && other.is_constant()) {
418
0
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
0
        return result;
421
0
    }
422
1.73k
    bigfield result(ctx);
423
1.73k
    result.binary_basis_limbs[0].maximum_value =
424
1.73k
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
1.73k
    result.binary_basis_limbs[1].maximum_value =
426
1.73k
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
1.73k
    result.binary_basis_limbs[2].maximum_value =
428
1.73k
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
1.73k
    result.binary_basis_limbs[3].maximum_value =
430
1.73k
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
1.73k
    if constexpr (HasPlookup<Builder>) {
433
1.73k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
1.73k
            !is_constant() && !other.is_constant()) {
435
1.36k
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
1.36k
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
1.36k
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
1.36k
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
1.36k
            limbconst = limbconst || prime_basis_limb.is_constant();
440
1.36k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
1.36k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
1.36k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
1.36k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
1.36k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
1.36k
            limbconst =
446
1.36k
                limbconst || (prime_basis_limb.get_witness_index() ==
447
1.36k
                              other.prime_basis_limb
448
1.36k
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
1.36k
            if (!limbconst) {
451
18
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
18
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
18
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
18
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
18
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
18
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
18
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
18
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
18
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
18
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
18
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
18
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
18
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
18
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
18
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
18
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
18
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
18
                          other.binary_basis_limbs[0].element.additive_constant);
469
18
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
18
                          other.binary_basis_limbs[1].element.additive_constant);
471
18
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
18
                          other.binary_basis_limbs[2].element.additive_constant);
473
18
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
18
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
18
                uint32_t xp(prime_basis_limb.witness_index);
477
18
                uint32_t yp(other.prime_basis_limb.witness_index);
478
18
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
18
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
18
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
18
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
18
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
18
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
18
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
18
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
18
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
18
                return result;
488
18
            }
489
1.36k
        }
490
1.73k
    }
491
492
1.72k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
1.72k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
1.72k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
1.72k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
1.72k
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
1.72k
    return result;
498
1.73k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEplERKS7_
Line
Count
Source
411
25
{
412
25
    reduction_check();
413
25
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
25
    Builder* ctx = context ? context : other.context;
416
417
25
    if (is_constant() && other.is_constant()) {
418
0
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
0
        return result;
421
0
    }
422
25
    bigfield result(ctx);
423
25
    result.binary_basis_limbs[0].maximum_value =
424
25
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
25
    result.binary_basis_limbs[1].maximum_value =
426
25
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
25
    result.binary_basis_limbs[2].maximum_value =
428
25
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
25
    result.binary_basis_limbs[3].maximum_value =
430
25
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
25
    if constexpr (HasPlookup<Builder>) {
433
25
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
25
            !is_constant() && !other.is_constant()) {
435
25
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
25
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
25
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
25
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
25
            limbconst = limbconst || prime_basis_limb.is_constant();
440
25
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
25
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
25
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
25
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
25
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
25
            limbconst =
446
25
                limbconst || (prime_basis_limb.get_witness_index() ==
447
25
                              other.prime_basis_limb
448
25
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
25
            if (!limbconst) {
451
1
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
1
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
1
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
1
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
1
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
1
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
1
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
1
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
1
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
1
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
1
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
1
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
1
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
1
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
1
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
1
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
1
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
1
                          other.binary_basis_limbs[0].element.additive_constant);
469
1
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
1
                          other.binary_basis_limbs[1].element.additive_constant);
471
1
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
1
                          other.binary_basis_limbs[2].element.additive_constant);
473
1
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
1
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
1
                uint32_t xp(prime_basis_limb.witness_index);
477
1
                uint32_t yp(other.prime_basis_limb.witness_index);
478
1
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
1
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
1
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
1
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
1
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
1
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
1
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
1
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
1
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
1
                return result;
488
1
            }
489
25
        }
490
25
    }
491
492
24
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
24
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
24
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
24
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
24
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
24
    return result;
498
25
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEplERKS9_
Line
Count
Source
411
32.8k
{
412
32.8k
    reduction_check();
413
32.8k
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
32.8k
    Builder* ctx = context ? context : other.context;
416
417
32.8k
    if (is_constant() && other.is_constant()) {
418
0
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
0
        return result;
421
0
    }
422
32.8k
    bigfield result(ctx);
423
32.8k
    result.binary_basis_limbs[0].maximum_value =
424
32.8k
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
32.8k
    result.binary_basis_limbs[1].maximum_value =
426
32.8k
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
32.8k
    result.binary_basis_limbs[2].maximum_value =
428
32.8k
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
32.8k
    result.binary_basis_limbs[3].maximum_value =
430
32.8k
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
32.8k
    if constexpr (HasPlookup<Builder>) {
433
32.8k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
32.8k
            !is_constant() && !other.is_constant()) {
435
26.4k
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
26.4k
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
26.4k
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
26.4k
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
26.4k
            limbconst = limbconst || prime_basis_limb.is_constant();
440
26.4k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
26.4k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
26.4k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
26.4k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
26.4k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
26.4k
            limbconst =
446
26.4k
                limbconst || (prime_basis_limb.get_witness_index() ==
447
26.4k
                              other.prime_basis_limb
448
26.4k
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
26.4k
            if (!limbconst) {
451
0
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
0
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
0
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
0
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
0
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
0
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
0
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
0
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
0
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
0
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
0
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
0
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
0
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
0
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
0
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
0
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
0
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
0
                          other.binary_basis_limbs[0].element.additive_constant);
469
0
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
0
                          other.binary_basis_limbs[1].element.additive_constant);
471
0
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
0
                          other.binary_basis_limbs[2].element.additive_constant);
473
0
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
0
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
0
                uint32_t xp(prime_basis_limb.witness_index);
477
0
                uint32_t yp(other.prime_basis_limb.witness_index);
478
0
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
0
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
0
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
0
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
0
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
0
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
0
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
0
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
0
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
0
                return result;
488
0
            }
489
26.4k
        }
490
32.8k
    }
491
492
32.8k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
32.8k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
32.8k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
32.8k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
32.8k
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
32.8k
    return result;
498
32.8k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEplERKS9_
Line
Count
Source
411
576
{
412
576
    reduction_check();
413
576
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
576
    Builder* ctx = context ? context : other.context;
416
417
576
    if (is_constant() && other.is_constant()) {
418
0
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
0
        return result;
421
0
    }
422
576
    bigfield result(ctx);
423
576
    result.binary_basis_limbs[0].maximum_value =
424
576
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
576
    result.binary_basis_limbs[1].maximum_value =
426
576
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
576
    result.binary_basis_limbs[2].maximum_value =
428
576
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
576
    result.binary_basis_limbs[3].maximum_value =
430
576
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
576
    if constexpr (HasPlookup<Builder>) {
433
576
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
576
            !is_constant() && !other.is_constant()) {
435
576
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
576
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
576
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
576
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
576
            limbconst = limbconst || prime_basis_limb.is_constant();
440
576
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
576
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
576
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
576
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
576
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
576
            limbconst =
446
576
                limbconst || (prime_basis_limb.get_witness_index() ==
447
576
                              other.prime_basis_limb
448
576
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
576
            if (!limbconst) {
451
0
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
0
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
0
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
0
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
0
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
0
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
0
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
0
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
0
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
0
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
0
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
0
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
0
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
0
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
0
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
0
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
0
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
0
                          other.binary_basis_limbs[0].element.additive_constant);
469
0
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
0
                          other.binary_basis_limbs[1].element.additive_constant);
471
0
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
0
                          other.binary_basis_limbs[2].element.additive_constant);
473
0
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
0
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
0
                uint32_t xp(prime_basis_limb.witness_index);
477
0
                uint32_t yp(other.prime_basis_limb.witness_index);
478
0
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
0
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
0
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
0
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
0
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
0
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
0
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
0
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
0
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
0
                return result;
488
0
            }
489
576
        }
490
576
    }
491
492
576
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
576
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
576
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
576
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
576
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
576
    return result;
498
576
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEplERKS7_
Line
Count
Source
411
1.34k
{
412
1.34k
    reduction_check();
413
1.34k
    other.reduction_check();
414
    // needed cause a constant doesn't have a valid context
415
1.34k
    Builder* ctx = context ? context : other.context;
416
417
1.34k
    if (is_constant() && other.is_constant()) {
418
0
        auto result = bigfield(ctx, uint256_t((get_value() + other.get_value()) % modulus_u512));
419
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
420
0
        return result;
421
0
    }
422
1.34k
    bigfield result(ctx);
423
1.34k
    result.binary_basis_limbs[0].maximum_value =
424
1.34k
        binary_basis_limbs[0].maximum_value + other.binary_basis_limbs[0].maximum_value;
425
1.34k
    result.binary_basis_limbs[1].maximum_value =
426
1.34k
        binary_basis_limbs[1].maximum_value + other.binary_basis_limbs[1].maximum_value;
427
1.34k
    result.binary_basis_limbs[2].maximum_value =
428
1.34k
        binary_basis_limbs[2].maximum_value + other.binary_basis_limbs[2].maximum_value;
429
1.34k
    result.binary_basis_limbs[3].maximum_value =
430
1.34k
        binary_basis_limbs[3].maximum_value + other.binary_basis_limbs[3].maximum_value;
431
432
1.34k
    if constexpr (HasPlookup<Builder>) {
433
1.34k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
434
1.34k
            !is_constant() && !other.is_constant()) {
435
1.30k
            bool limbconst = binary_basis_limbs[0].element.is_constant();
436
1.30k
            limbconst = limbconst || binary_basis_limbs[1].element.is_constant();
437
1.30k
            limbconst = limbconst || binary_basis_limbs[2].element.is_constant();
438
1.30k
            limbconst = limbconst || binary_basis_limbs[3].element.is_constant();
439
1.30k
            limbconst = limbconst || prime_basis_limb.is_constant();
440
1.30k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
441
1.30k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
442
1.30k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
443
1.30k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
444
1.30k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
445
1.30k
            limbconst =
446
1.30k
                limbconst || (prime_basis_limb.get_witness_index() ==
447
1.30k
                              other.prime_basis_limb
448
1.30k
                                  .get_witness_index()); // We are comparing if the bigfield elements are exactly the
449
                                                         // same object, so we compare the unnormalized witness indices
450
1.30k
            if (!limbconst) {
451
0
                std::pair<uint32_t, bb::fr> x0{ binary_basis_limbs[0].element.witness_index,
452
0
                                                binary_basis_limbs[0].element.multiplicative_constant };
453
0
                std::pair<uint32_t, bb::fr> x1{ binary_basis_limbs[1].element.witness_index,
454
0
                                                binary_basis_limbs[1].element.multiplicative_constant };
455
0
                std::pair<uint32_t, bb::fr> x2{ binary_basis_limbs[2].element.witness_index,
456
0
                                                binary_basis_limbs[2].element.multiplicative_constant };
457
0
                std::pair<uint32_t, bb::fr> x3{ binary_basis_limbs[3].element.witness_index,
458
0
                                                binary_basis_limbs[3].element.multiplicative_constant };
459
0
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
460
0
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
461
0
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
462
0
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
463
0
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
464
0
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
465
0
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
466
0
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
467
0
                bb::fr c0(binary_basis_limbs[0].element.additive_constant +
468
0
                          other.binary_basis_limbs[0].element.additive_constant);
469
0
                bb::fr c1(binary_basis_limbs[1].element.additive_constant +
470
0
                          other.binary_basis_limbs[1].element.additive_constant);
471
0
                bb::fr c2(binary_basis_limbs[2].element.additive_constant +
472
0
                          other.binary_basis_limbs[2].element.additive_constant);
473
0
                bb::fr c3(binary_basis_limbs[3].element.additive_constant +
474
0
                          other.binary_basis_limbs[3].element.additive_constant);
475
476
0
                uint32_t xp(prime_basis_limb.witness_index);
477
0
                uint32_t yp(other.prime_basis_limb.witness_index);
478
0
                bb::fr cp(prime_basis_limb.additive_constant + other.prime_basis_limb.additive_constant);
479
0
                const auto output_witnesses = ctx->evaluate_non_native_field_addition(
480
0
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
481
0
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
482
0
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
483
0
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
484
0
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
485
0
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
486
0
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
487
0
                return result;
488
0
            }
489
1.30k
        }
490
1.34k
    }
491
492
1.34k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + other.binary_basis_limbs[0].element;
493
1.34k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + other.binary_basis_limbs[1].element;
494
1.34k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + other.binary_basis_limbs[2].element;
495
1.34k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + other.binary_basis_limbs[3].element;
496
1.34k
    result.prime_basis_limb = prime_basis_limb + other.prime_basis_limb;
497
1.34k
    return result;
498
1.34k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEplERKS7_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEplERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEplERKS9_
499
500
/**
501
 * @brief Create constraints for summing three
502
 * bigfield elements efficiently
503
 *
504
 * @tparam Builder
505
 * @tparam T
506
 * @param add_a
507
 * @param add_b
508
 * @return The sum of three terms
509
 */
510
template <typename Builder, typename T>
511
bigfield<Builder, T> bigfield<Builder, T>::add_two(const bigfield& add_a, const bigfield& add_b) const
512
0
{
513
0
    reduction_check();
514
0
    add_a.reduction_check();
515
0
    add_b.reduction_check();
516
517
0
    Builder* ctx = (context == nullptr) ? (add_a.context == nullptr ? add_b.context : add_a.context) : context;
518
519
0
    if (is_constant() && add_a.is_constant() && add_b.is_constant()) {
520
0
        auto result = bigfield(ctx, uint256_t((get_value() + add_a.get_value() + add_b.get_value()) % modulus_u512));
521
0
        result.set_origin_tag(OriginTag(this->get_origin_tag(), add_a.get_origin_tag(), add_b.get_origin_tag()));
522
0
        return result;
523
0
    }
524
525
0
    bigfield result(ctx);
526
0
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value +
527
0
                                                 add_a.binary_basis_limbs[0].maximum_value +
528
0
                                                 add_b.binary_basis_limbs[0].maximum_value;
529
0
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value +
530
0
                                                 add_a.binary_basis_limbs[1].maximum_value +
531
0
                                                 add_b.binary_basis_limbs[1].maximum_value;
532
0
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value +
533
0
                                                 add_a.binary_basis_limbs[2].maximum_value +
534
0
                                                 add_b.binary_basis_limbs[2].maximum_value;
535
0
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value +
536
0
                                                 add_a.binary_basis_limbs[3].maximum_value +
537
0
                                                 add_b.binary_basis_limbs[3].maximum_value;
538
539
0
    result.binary_basis_limbs[0].element =
540
0
        binary_basis_limbs[0].element.add_two(add_a.binary_basis_limbs[0].element, add_b.binary_basis_limbs[0].element);
541
0
    result.binary_basis_limbs[1].element =
542
0
        binary_basis_limbs[1].element.add_two(add_a.binary_basis_limbs[1].element, add_b.binary_basis_limbs[1].element);
543
0
    result.binary_basis_limbs[2].element =
544
0
        binary_basis_limbs[2].element.add_two(add_a.binary_basis_limbs[2].element, add_b.binary_basis_limbs[2].element);
545
0
    result.binary_basis_limbs[3].element =
546
0
        binary_basis_limbs[3].element.add_two(add_a.binary_basis_limbs[3].element, add_b.binary_basis_limbs[3].element);
547
0
    result.prime_basis_limb = prime_basis_limb.add_two(add_a.prime_basis_limb, add_b.prime_basis_limb);
548
0
    result.set_origin_tag(OriginTag(this->get_origin_tag(), add_a.get_origin_tag(), add_b.get_origin_tag()));
549
0
    return result;
550
0
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE7add_twoERKS6_S8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE7add_twoERKS6_S8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE7add_twoERKS8_SA_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E7add_twoERKS7_S9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE7add_twoERKS7_S9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE7add_twoERKS7_S9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE7add_twoERKS9_SB_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE7add_twoERKS9_SB_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE7add_twoERKS7_S9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE7add_twoERKS7_S9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE7add_twoERKS9_SB_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE7add_twoERKS9_SB_
551
552
// to make sure we don't go to negative values, add p before subtracting other
553
/**
554
 * Subtraction operator.
555
 *
556
 * Like operator+, we use lazy reduction techniques to save on field reductions.
557
 *
558
 * Instead of computing `*this - other`, we compute offset X and compute:
559
 * `*this + X - other`
560
 * This ensures we do not underflow!
561
 *
562
 * Offset `X` will be a multiple of our bigfield modulus `p`
563
 *
564
 * i.e `X = m * p`
565
 *
566
 * It is NOT enough to ensure that the integer value of `*this + X - other` does not underflow.
567
 * We must ALSO ensure that each LIMB of the result does not underflow
568
 *
569
 * We must compute the MINIMUM value of `m` that ensures that none of the bigfield limbs will underflow!
570
 *
571
 * i.e. We must compute the MINIMUM value of `m` such that, for each limb `i`, the following result is positive:
572
 *
573
 * *this.limb[i] + X.limb[i] - other.limb[i]
574
 **/
575
template <typename Builder, typename T>
576
bigfield<Builder, T> bigfield<Builder, T>::operator-(const bigfield& other) const
577
2.02M
{
578
2.02M
    Builder* ctx = context ? context : other.context;
579
2.02M
    reduction_check();
580
2.02M
    other.reduction_check();
581
582
2.02M
    if (is_constant() && other.is_constant()) {
583
9.57k
        uint512_t left = get_value() % modulus_u512;
584
9.57k
        uint512_t right = other.get_value() % modulus_u512;
585
9.57k
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
9.57k
        auto result = bigfield(ctx, uint256_t(out.lo));
588
9.57k
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
9.57k
        return result;
590
9.57k
    }
591
592
2.02M
    if (other.is_constant()) {
593
12.2k
        uint512_t right = other.get_value() % modulus_u512;
594
12.2k
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
12.2k
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
12.2k
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
2.00M
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
2.00M
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
2.00M
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
2.00M
    uint256_t limb_1_maximum_value =
632
2.00M
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
2.00M
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
2.00M
    uint256_t limb_2_maximum_value =
637
2.00M
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
2.00M
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
2.00M
    uint256_t limb_3_maximum_value =
641
2.00M
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
2.00M
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
4.10M
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
2.09M
        constant_to_add += modulus_u512;
655
2.09M
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
2.00M
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
2.00M
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
2.00M
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
2.00M
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
2.00M
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
2.00M
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
2.00M
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
2.00M
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
2.00M
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
2.00M
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
2.00M
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
2.00M
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
2.00M
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
2.00M
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
2.00M
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
2.00M
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
2.00M
    if constexpr (HasPlookup<Builder>) {
702
2.00M
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
2.00M
            !is_constant() && !other.is_constant()) {
704
879k
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
879k
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
879k
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
879k
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
879k
            limbconst = limbconst || prime_basis_limb.is_constant();
709
879k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
879k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
879k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
879k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
879k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
879k
            limbconst =
715
879k
                limbconst ||
716
879k
                (prime_basis_limb.witness_index ==
717
879k
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
879k
            if (!limbconst) {
720
879k
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
879k
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
879k
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
879k
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
879k
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
879k
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
879k
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
879k
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
879k
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
879k
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
879k
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
879k
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
879k
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
879k
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
879k
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
879k
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
879k
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
879k
                          other.binary_basis_limbs[0].element.additive_constant);
738
879k
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
879k
                          other.binary_basis_limbs[1].element.additive_constant);
740
879k
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
879k
                          other.binary_basis_limbs[2].element.additive_constant);
742
879k
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
879k
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
879k
                uint32_t xp(prime_basis_limb.witness_index);
746
879k
                uint32_t yp(other.prime_basis_limb.witness_index);
747
879k
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
879k
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
879k
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
879k
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
879k
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
879k
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
879k
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
879k
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
879k
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
879k
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
879k
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
879k
                return result;
762
879k
            }
763
879k
        }
764
2.00M
    }
765
766
1.12M
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
1.12M
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
1.12M
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
1.12M
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
1.12M
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
1.12M
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
1.12M
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
1.12M
    result.prime_basis_limb -= other.prime_basis_limb;
778
1.12M
    return result;
779
2.00M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEmiERKS6_
Line
Count
Source
577
1.84M
{
578
1.84M
    Builder* ctx = context ? context : other.context;
579
1.84M
    reduction_check();
580
1.84M
    other.reduction_check();
581
582
1.84M
    if (is_constant() && other.is_constant()) {
583
9.07k
        uint512_t left = get_value() % modulus_u512;
584
9.07k
        uint512_t right = other.get_value() % modulus_u512;
585
9.07k
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
9.07k
        auto result = bigfield(ctx, uint256_t(out.lo));
588
9.07k
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
9.07k
        return result;
590
9.07k
    }
591
592
1.83M
    if (other.is_constant()) {
593
12.2k
        uint512_t right = other.get_value() % modulus_u512;
594
12.2k
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
12.2k
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
12.2k
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
1.82M
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
1.82M
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
1.82M
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
1.82M
    uint256_t limb_1_maximum_value =
632
1.82M
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
1.82M
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
1.82M
    uint256_t limb_2_maximum_value =
637
1.82M
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
1.82M
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
1.82M
    uint256_t limb_3_maximum_value =
641
1.82M
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
1.82M
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
3.72M
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
1.90M
        constant_to_add += modulus_u512;
655
1.90M
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
1.82M
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
1.82M
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
1.82M
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
1.82M
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
1.82M
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
1.82M
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
1.82M
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
1.82M
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
1.82M
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
1.82M
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
1.82M
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
1.82M
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
1.82M
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
1.82M
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
1.82M
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
1.82M
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
1.82M
    if constexpr (HasPlookup<Builder>) {
702
1.82M
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
1.82M
            !is_constant() && !other.is_constant()) {
704
807k
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
807k
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
807k
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
807k
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
807k
            limbconst = limbconst || prime_basis_limb.is_constant();
709
807k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
807k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
807k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
807k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
807k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
807k
            limbconst =
715
807k
                limbconst ||
716
807k
                (prime_basis_limb.witness_index ==
717
807k
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
807k
            if (!limbconst) {
720
807k
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
807k
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
807k
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
807k
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
807k
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
807k
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
807k
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
807k
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
807k
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
807k
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
807k
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
807k
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
807k
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
807k
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
807k
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
807k
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
807k
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
807k
                          other.binary_basis_limbs[0].element.additive_constant);
738
807k
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
807k
                          other.binary_basis_limbs[1].element.additive_constant);
740
807k
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
807k
                          other.binary_basis_limbs[2].element.additive_constant);
742
807k
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
807k
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
807k
                uint32_t xp(prime_basis_limb.witness_index);
746
807k
                uint32_t yp(other.prime_basis_limb.witness_index);
747
807k
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
807k
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
807k
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
807k
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
807k
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
807k
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
807k
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
807k
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
807k
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
807k
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
807k
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
807k
                return result;
762
807k
            }
763
807k
        }
764
1.82M
    }
765
766
1.01M
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
1.01M
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
1.01M
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
1.01M
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
1.01M
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
1.01M
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
1.01M
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
1.01M
    result.prime_basis_limb -= other.prime_basis_limb;
778
1.01M
    return result;
779
1.82M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEmiERKS6_
Line
Count
Source
577
653
{
578
653
    Builder* ctx = context ? context : other.context;
579
653
    reduction_check();
580
653
    other.reduction_check();
581
582
653
    if (is_constant() && other.is_constant()) {
583
0
        uint512_t left = get_value() % modulus_u512;
584
0
        uint512_t right = other.get_value() % modulus_u512;
585
0
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
0
        auto result = bigfield(ctx, uint256_t(out.lo));
588
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
0
        return result;
590
0
    }
591
592
653
    if (other.is_constant()) {
593
0
        uint512_t right = other.get_value() % modulus_u512;
594
0
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
0
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
0
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
653
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
653
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
653
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
653
    uint256_t limb_1_maximum_value =
632
653
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
653
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
653
    uint256_t limb_2_maximum_value =
637
653
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
653
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
653
    uint256_t limb_3_maximum_value =
641
653
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
653
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
1.34k
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
690
        constant_to_add += modulus_u512;
655
690
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
653
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
653
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
653
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
653
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
653
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
653
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
653
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
653
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
653
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
653
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
653
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
653
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
653
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
653
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
653
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
653
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
653
    if constexpr (HasPlookup<Builder>) {
702
653
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
653
            !is_constant() && !other.is_constant()) {
704
641
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
641
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
641
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
641
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
641
            limbconst = limbconst || prime_basis_limb.is_constant();
709
641
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
641
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
641
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
641
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
641
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
641
            limbconst =
715
641
                limbconst ||
716
641
                (prime_basis_limb.witness_index ==
717
641
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
641
            if (!limbconst) {
720
641
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
641
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
641
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
641
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
641
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
641
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
641
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
641
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
641
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
641
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
641
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
641
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
641
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
641
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
641
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
641
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
641
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
641
                          other.binary_basis_limbs[0].element.additive_constant);
738
641
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
641
                          other.binary_basis_limbs[1].element.additive_constant);
740
641
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
641
                          other.binary_basis_limbs[2].element.additive_constant);
742
641
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
641
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
641
                uint32_t xp(prime_basis_limb.witness_index);
746
641
                uint32_t yp(other.prime_basis_limb.witness_index);
747
641
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
641
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
641
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
641
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
641
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
641
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
641
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
641
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
641
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
641
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
641
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
641
                return result;
762
641
            }
763
641
        }
764
653
    }
765
766
12
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
12
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
12
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
12
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
12
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
12
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
12
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
12
    result.prime_basis_limb -= other.prime_basis_limb;
778
12
    return result;
779
653
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEmiERKS8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EmiERKS7_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEmiERKS7_
Line
Count
Source
577
7.23k
{
578
7.23k
    Builder* ctx = context ? context : other.context;
579
7.23k
    reduction_check();
580
7.23k
    other.reduction_check();
581
582
7.23k
    if (is_constant() && other.is_constant()) {
583
18
        uint512_t left = get_value() % modulus_u512;
584
18
        uint512_t right = other.get_value() % modulus_u512;
585
18
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
18
        auto result = bigfield(ctx, uint256_t(out.lo));
588
18
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
18
        return result;
590
18
    }
591
592
7.21k
    if (other.is_constant()) {
593
0
        uint512_t right = other.get_value() % modulus_u512;
594
0
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
0
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
0
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
7.21k
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
7.21k
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
7.21k
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
7.21k
    uint256_t limb_1_maximum_value =
632
7.21k
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
7.21k
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
7.21k
    uint256_t limb_2_maximum_value =
637
7.21k
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
7.21k
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
7.21k
    uint256_t limb_3_maximum_value =
641
7.21k
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
7.21k
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
14.9k
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
7.75k
        constant_to_add += modulus_u512;
655
7.75k
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
7.21k
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
7.21k
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
7.21k
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
7.21k
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
7.21k
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
7.21k
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
7.21k
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
7.21k
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
7.21k
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
7.21k
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
7.21k
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
7.21k
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
7.21k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
7.21k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
7.21k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
7.21k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
7.21k
    if constexpr (HasPlookup<Builder>) {
702
7.21k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
7.21k
            !is_constant() && !other.is_constant()) {
704
2.83k
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
2.83k
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
2.83k
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
2.83k
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
2.83k
            limbconst = limbconst || prime_basis_limb.is_constant();
709
2.83k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
2.83k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
2.83k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
2.83k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
2.83k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
2.83k
            limbconst =
715
2.83k
                limbconst ||
716
2.83k
                (prime_basis_limb.witness_index ==
717
2.83k
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
2.83k
            if (!limbconst) {
720
2.83k
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
2.83k
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
2.83k
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
2.83k
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
2.83k
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
2.83k
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
2.83k
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
2.83k
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
2.83k
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
2.83k
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
2.83k
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
2.83k
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
2.83k
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
2.83k
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
2.83k
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
2.83k
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
2.83k
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
2.83k
                          other.binary_basis_limbs[0].element.additive_constant);
738
2.83k
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
2.83k
                          other.binary_basis_limbs[1].element.additive_constant);
740
2.83k
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
2.83k
                          other.binary_basis_limbs[2].element.additive_constant);
742
2.83k
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
2.83k
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
2.83k
                uint32_t xp(prime_basis_limb.witness_index);
746
2.83k
                uint32_t yp(other.prime_basis_limb.witness_index);
747
2.83k
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
2.83k
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
2.83k
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
2.83k
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
2.83k
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
2.83k
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
2.83k
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
2.83k
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
2.83k
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
2.83k
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
2.83k
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
2.83k
                return result;
762
2.83k
            }
763
2.83k
        }
764
7.21k
    }
765
766
4.38k
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
4.38k
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
4.38k
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
4.38k
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
4.38k
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
4.38k
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
4.38k
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
4.38k
    result.prime_basis_limb -= other.prime_basis_limb;
778
4.38k
    return result;
779
7.21k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEmiERKS7_
Line
Count
Source
577
26
{
578
26
    Builder* ctx = context ? context : other.context;
579
26
    reduction_check();
580
26
    other.reduction_check();
581
582
26
    if (is_constant() && other.is_constant()) {
583
0
        uint512_t left = get_value() % modulus_u512;
584
0
        uint512_t right = other.get_value() % modulus_u512;
585
0
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
0
        auto result = bigfield(ctx, uint256_t(out.lo));
588
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
0
        return result;
590
0
    }
591
592
26
    if (other.is_constant()) {
593
0
        uint512_t right = other.get_value() % modulus_u512;
594
0
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
0
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
0
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
26
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
26
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
26
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
26
    uint256_t limb_1_maximum_value =
632
26
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
26
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
26
    uint256_t limb_2_maximum_value =
637
26
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
26
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
26
    uint256_t limb_3_maximum_value =
641
26
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
26
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
28
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
2
        constant_to_add += modulus_u512;
655
2
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
26
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
26
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
26
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
26
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
26
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
26
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
26
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
26
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
26
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
26
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
26
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
26
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
26
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
26
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
26
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
26
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
26
    if constexpr (HasPlookup<Builder>) {
702
26
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
26
            !is_constant() && !other.is_constant()) {
704
26
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
26
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
26
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
26
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
26
            limbconst = limbconst || prime_basis_limb.is_constant();
709
26
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
26
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
26
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
26
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
26
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
26
            limbconst =
715
26
                limbconst ||
716
26
                (prime_basis_limb.witness_index ==
717
26
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
26
            if (!limbconst) {
720
26
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
26
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
26
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
26
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
26
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
26
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
26
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
26
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
26
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
26
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
26
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
26
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
26
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
26
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
26
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
26
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
26
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
26
                          other.binary_basis_limbs[0].element.additive_constant);
738
26
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
26
                          other.binary_basis_limbs[1].element.additive_constant);
740
26
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
26
                          other.binary_basis_limbs[2].element.additive_constant);
742
26
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
26
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
26
                uint32_t xp(prime_basis_limb.witness_index);
746
26
                uint32_t yp(other.prime_basis_limb.witness_index);
747
26
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
26
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
26
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
26
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
26
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
26
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
26
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
26
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
26
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
26
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
26
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
26
                return result;
762
26
            }
763
26
        }
764
26
    }
765
766
0
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
0
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
0
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
0
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
0
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
0
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
0
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
0
    result.prime_basis_limb -= other.prime_basis_limb;
778
0
    return result;
779
26
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEmiERKS9_
Line
Count
Source
577
162k
{
578
162k
    Builder* ctx = context ? context : other.context;
579
162k
    reduction_check();
580
162k
    other.reduction_check();
581
582
162k
    if (is_constant() && other.is_constant()) {
583
432
        uint512_t left = get_value() % modulus_u512;
584
432
        uint512_t right = other.get_value() % modulus_u512;
585
432
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
432
        auto result = bigfield(ctx, uint256_t(out.lo));
588
432
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
432
        return result;
590
432
    }
591
592
161k
    if (other.is_constant()) {
593
0
        uint512_t right = other.get_value() % modulus_u512;
594
0
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
0
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
0
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
161k
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
161k
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
161k
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
161k
    uint256_t limb_1_maximum_value =
632
161k
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
161k
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
161k
    uint256_t limb_2_maximum_value =
637
161k
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
161k
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
161k
    uint256_t limb_3_maximum_value =
641
161k
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
161k
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
333k
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
171k
        constant_to_add += modulus_u512;
655
171k
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
161k
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
161k
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
161k
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
161k
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
161k
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
161k
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
161k
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
161k
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
161k
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
161k
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
161k
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
161k
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
161k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
161k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
161k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
161k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
161k
    if constexpr (HasPlookup<Builder>) {
702
161k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
161k
            !is_constant() && !other.is_constant()) {
704
63.6k
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
63.6k
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
63.6k
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
63.6k
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
63.6k
            limbconst = limbconst || prime_basis_limb.is_constant();
709
63.6k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
63.6k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
63.6k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
63.6k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
63.6k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
63.6k
            limbconst =
715
63.6k
                limbconst ||
716
63.6k
                (prime_basis_limb.witness_index ==
717
63.6k
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
63.6k
            if (!limbconst) {
720
63.6k
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
63.6k
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
63.6k
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
63.6k
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
63.6k
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
63.6k
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
63.6k
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
63.6k
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
63.6k
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
63.6k
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
63.6k
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
63.6k
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
63.6k
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
63.6k
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
63.6k
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
63.6k
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
63.6k
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
63.6k
                          other.binary_basis_limbs[0].element.additive_constant);
738
63.6k
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
63.6k
                          other.binary_basis_limbs[1].element.additive_constant);
740
63.6k
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
63.6k
                          other.binary_basis_limbs[2].element.additive_constant);
742
63.6k
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
63.6k
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
63.6k
                uint32_t xp(prime_basis_limb.witness_index);
746
63.6k
                uint32_t yp(other.prime_basis_limb.witness_index);
747
63.6k
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
63.6k
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
63.6k
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
63.6k
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
63.6k
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
63.6k
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
63.6k
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
63.6k
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
63.6k
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
63.6k
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
63.6k
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
63.6k
                return result;
762
63.6k
            }
763
63.6k
        }
764
161k
    }
765
766
97.9k
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
97.9k
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
97.9k
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
97.9k
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
97.9k
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
97.9k
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
97.9k
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
97.9k
    result.prime_basis_limb -= other.prime_basis_limb;
778
97.9k
    return result;
779
161k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEmiERKS9_
Line
Count
Source
577
576
{
578
576
    Builder* ctx = context ? context : other.context;
579
576
    reduction_check();
580
576
    other.reduction_check();
581
582
576
    if (is_constant() && other.is_constant()) {
583
0
        uint512_t left = get_value() % modulus_u512;
584
0
        uint512_t right = other.get_value() % modulus_u512;
585
0
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
0
        auto result = bigfield(ctx, uint256_t(out.lo));
588
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
0
        return result;
590
0
    }
591
592
576
    if (other.is_constant()) {
593
0
        uint512_t right = other.get_value() % modulus_u512;
594
0
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
0
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
0
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
576
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
576
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
576
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
576
    uint256_t limb_1_maximum_value =
632
576
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
576
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
576
    uint256_t limb_2_maximum_value =
637
576
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
576
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
576
    uint256_t limb_3_maximum_value =
641
576
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
576
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
576
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
0
        constant_to_add += modulus_u512;
655
0
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
576
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
576
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
576
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
576
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
576
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
576
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
576
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
576
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
576
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
576
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
576
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
576
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
576
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
576
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
576
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
576
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
576
    if constexpr (HasPlookup<Builder>) {
702
576
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
576
            !is_constant() && !other.is_constant()) {
704
576
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
576
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
576
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
576
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
576
            limbconst = limbconst || prime_basis_limb.is_constant();
709
576
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
576
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
576
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
576
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
576
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
576
            limbconst =
715
576
                limbconst ||
716
576
                (prime_basis_limb.witness_index ==
717
576
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
576
            if (!limbconst) {
720
576
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
576
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
576
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
576
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
576
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
576
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
576
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
576
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
576
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
576
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
576
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
576
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
576
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
576
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
576
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
576
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
576
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
576
                          other.binary_basis_limbs[0].element.additive_constant);
738
576
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
576
                          other.binary_basis_limbs[1].element.additive_constant);
740
576
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
576
                          other.binary_basis_limbs[2].element.additive_constant);
742
576
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
576
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
576
                uint32_t xp(prime_basis_limb.witness_index);
746
576
                uint32_t yp(other.prime_basis_limb.witness_index);
747
576
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
576
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
576
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
576
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
576
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
576
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
576
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
576
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
576
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
576
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
576
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
576
                return result;
762
576
            }
763
576
        }
764
576
    }
765
766
0
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
0
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
0
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
0
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
0
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
0
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
0
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
0
    result.prime_basis_limb -= other.prime_basis_limb;
778
0
    return result;
779
576
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEmiERKS7_
Line
Count
Source
577
11.4k
{
578
11.4k
    Builder* ctx = context ? context : other.context;
579
11.4k
    reduction_check();
580
11.4k
    other.reduction_check();
581
582
11.4k
    if (is_constant() && other.is_constant()) {
583
50
        uint512_t left = get_value() % modulus_u512;
584
50
        uint512_t right = other.get_value() % modulus_u512;
585
50
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
50
        auto result = bigfield(ctx, uint256_t(out.lo));
588
50
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
50
        return result;
590
50
    }
591
592
11.3k
    if (other.is_constant()) {
593
15
        uint512_t right = other.get_value() % modulus_u512;
594
15
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
15
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
15
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
11.3k
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
11.3k
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
11.3k
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
11.3k
    uint256_t limb_1_maximum_value =
632
11.3k
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
11.3k
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
11.3k
    uint256_t limb_2_maximum_value =
637
11.3k
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
11.3k
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
11.3k
    uint256_t limb_3_maximum_value =
641
11.3k
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
11.3k
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
23.0k
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
11.6k
        constant_to_add += modulus_u512;
655
11.6k
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
11.3k
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
11.3k
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
11.3k
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
11.3k
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
11.3k
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
11.3k
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
11.3k
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
11.3k
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
11.3k
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
11.3k
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
11.3k
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
11.3k
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
11.3k
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
11.3k
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
11.3k
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
11.3k
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
11.3k
    if constexpr (HasPlookup<Builder>) {
702
11.3k
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
11.3k
            !is_constant() && !other.is_constant()) {
704
4.50k
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
4.50k
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
4.50k
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
4.50k
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
4.50k
            limbconst = limbconst || prime_basis_limb.is_constant();
709
4.50k
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
4.50k
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
4.50k
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
4.50k
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
4.50k
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
4.50k
            limbconst =
715
4.50k
                limbconst ||
716
4.50k
                (prime_basis_limb.witness_index ==
717
4.50k
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
4.50k
            if (!limbconst) {
720
4.50k
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
4.50k
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
4.50k
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
4.50k
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
4.50k
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
4.50k
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
4.50k
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
4.50k
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
4.50k
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
4.50k
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
4.50k
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
4.50k
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
4.50k
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
4.50k
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
4.50k
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
4.50k
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
4.50k
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
4.50k
                          other.binary_basis_limbs[0].element.additive_constant);
738
4.50k
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
4.50k
                          other.binary_basis_limbs[1].element.additive_constant);
740
4.50k
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
4.50k
                          other.binary_basis_limbs[2].element.additive_constant);
742
4.50k
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
4.50k
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
4.50k
                uint32_t xp(prime_basis_limb.witness_index);
746
4.50k
                uint32_t yp(other.prime_basis_limb.witness_index);
747
4.50k
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
4.50k
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
4.50k
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
4.50k
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
4.50k
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
4.50k
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
4.50k
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
4.50k
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
4.50k
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
4.50k
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
4.50k
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
4.50k
                return result;
762
4.50k
            }
763
4.50k
        }
764
11.3k
    }
765
766
6.83k
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
6.83k
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
6.83k
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
6.83k
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
6.83k
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
6.83k
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
6.83k
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
6.83k
    result.prime_basis_limb -= other.prime_basis_limb;
778
6.83k
    return result;
779
11.3k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEmiERKS7_
Line
Count
Source
577
20
{
578
20
    Builder* ctx = context ? context : other.context;
579
20
    reduction_check();
580
20
    other.reduction_check();
581
582
20
    if (is_constant() && other.is_constant()) {
583
0
        uint512_t left = get_value() % modulus_u512;
584
0
        uint512_t right = other.get_value() % modulus_u512;
585
0
        uint512_t out = (left + modulus_u512 - right) % modulus_u512;
586
587
0
        auto result = bigfield(ctx, uint256_t(out.lo));
588
0
        result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
589
0
        return result;
590
0
    }
591
592
20
    if (other.is_constant()) {
593
0
        uint512_t right = other.get_value() % modulus_u512;
594
0
        uint512_t neg_right = (modulus_u512 - right) % modulus_u512;
595
0
        return operator+(bigfield(ctx, uint256_t(neg_right.lo)));
596
0
    }
597
598
    /**
599
     * Plookup bigfield subtractoin
600
     *
601
     * We have a special addition gate we can toggle, that will compute: (w_1 + w_4 - w_4_omega + q_arith = 0)
602
     * This is in addition to the regular addition gate
603
     *
604
     * We can arrange our wires in memory like this:
605
     *
606
     *   |  1  |  2  |  3  |  4  |
607
     *   |-----|-----|-----|-----|
608
     *   | b.p | a.0 | b.0 | c.p | (b.p + c.p - a.p = 0) AND (a.0 - b.0 - c.0 = 0)
609
     *   | a.p | a.1 | b.1 | c.0 | (a.1 - b.1 - c.1 = 0)
610
     *   | a.2 | b.2 | c.2 | c.1 | (a.2 - b.2 - c.2 = 0)
611
     *   | a.3 | b.3 | c.3 | --- | (a.3 - b.3 - c.3 = 0)
612
     *
613
     **/
614
615
20
    bigfield result(ctx);
616
617
    /**
618
     * Step 1: For each limb compute the MAXIMUM value we will have to borrow from the next significant limb
619
     *
620
     * i.e. if we assume that `*this = 0` and `other = other.maximum_value`, how many bits do we need to borrow from
621
     * the next significant limb to ensure each limb value is positive?
622
     *
623
     * N.B. for this segment `maximum_value` really refers to maximum NEGATIVE value of the result
624
     **/
625
20
    uint256_t limb_0_maximum_value = other.binary_basis_limbs[0].maximum_value;
626
627
    // Compute maximum shift factor for limb_0
628
20
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
629
630
    // Compute the maximum negative value of limb_1, including the bits limb_0 may need to borrow
631
20
    uint256_t limb_1_maximum_value =
632
20
        other.binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
633
634
    // repeat the above for the remaining limbs
635
20
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
636
20
    uint256_t limb_2_maximum_value =
637
20
        other.binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
638
20
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
639
640
20
    uint256_t limb_3_maximum_value =
641
20
        other.binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
642
643
    /**
644
     * Step 2: Compute the constant value `X = m * p` we must add to the result to ensure EVERY limb is >= 0
645
     *
646
     * We need to find a value `X` where `X.limb[3] > limb_3_maximum_value`.
647
     * As long as the above holds, we can borrow bits from X.limb[3] to ensure less significant limbs are positive
648
     *
649
     * Start by setting constant_to_add = p
650
     **/
651
20
    uint512_t constant_to_add = modulus_u512;
652
    // add a large enough multiple of p to not get negative result in subtraction
653
40
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
654
20
        constant_to_add += modulus_u512;
655
20
    }
656
657
    /**
658
     * Step 3: Compute offset terms t0, t1, t2, t3 that we add to our result to ensure each limb is positive
659
     *
660
     * t3 represents the value we are BORROWING from constant_to_add.limb[3]
661
     * t2, t1, t0 are the terms we will ADD to constant_to_add.limb[2], constant_to_add.limb[1],
662
     *constant_to_add.limb[0]
663
     *
664
     * i.e. The net value we add to `constant_to_add` is 0. We must ensure that:
665
     * t3 = t0 + (t1 << NUM_LIMB_BITS) + (t2 << NUM_LIMB_BITS * 2)
666
     *
667
     * e.g. the value we borrow to produce t0 is subtracted from t1,
668
     *      the value we borrow from t1 is subtracted from t2
669
     *      the value we borrow from t2 is equal to t3
670
     **/
671
20
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
672
20
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
673
20
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
674
20
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
675
676
    /**
677
     * Compute the limbs of `constant_to_add`, including our offset terms t0, t1, t2, t3 that ensure each result
678
     *limb is positive
679
     **/
680
20
    uint256_t to_add_0 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS)) + t0;
681
20
    uint256_t to_add_1 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2)) + t1;
682
20
    uint256_t to_add_2 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3)) + t2;
683
20
    uint256_t to_add_3 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)) - t3;
684
685
    /**
686
     * Update the maximum possible value of the result. We assume here that (*this.value) = 0
687
     **/
688
20
    result.binary_basis_limbs[0].maximum_value = binary_basis_limbs[0].maximum_value + to_add_0;
689
20
    result.binary_basis_limbs[1].maximum_value = binary_basis_limbs[1].maximum_value + to_add_1;
690
20
    result.binary_basis_limbs[2].maximum_value = binary_basis_limbs[2].maximum_value + to_add_2;
691
20
    result.binary_basis_limbs[3].maximum_value = binary_basis_limbs[3].maximum_value + to_add_3;
692
693
    /**
694
     * Compute the binary basis limbs of our result
695
     **/
696
20
    result.binary_basis_limbs[0].element = binary_basis_limbs[0].element + bb::fr(to_add_0);
697
20
    result.binary_basis_limbs[1].element = binary_basis_limbs[1].element + bb::fr(to_add_1);
698
20
    result.binary_basis_limbs[2].element = binary_basis_limbs[2].element + bb::fr(to_add_2);
699
20
    result.binary_basis_limbs[3].element = binary_basis_limbs[3].element + bb::fr(to_add_3);
700
701
20
    if constexpr (HasPlookup<Builder>) {
702
20
        if (prime_basis_limb.multiplicative_constant == 1 && other.prime_basis_limb.multiplicative_constant == 1 &&
703
20
            !is_constant() && !other.is_constant()) {
704
20
            bool limbconst = result.binary_basis_limbs[0].element.is_constant();
705
20
            limbconst = limbconst || result.binary_basis_limbs[1].element.is_constant();
706
20
            limbconst = limbconst || result.binary_basis_limbs[2].element.is_constant();
707
20
            limbconst = limbconst || result.binary_basis_limbs[3].element.is_constant();
708
20
            limbconst = limbconst || prime_basis_limb.is_constant();
709
20
            limbconst = limbconst || other.binary_basis_limbs[0].element.is_constant();
710
20
            limbconst = limbconst || other.binary_basis_limbs[1].element.is_constant();
711
20
            limbconst = limbconst || other.binary_basis_limbs[2].element.is_constant();
712
20
            limbconst = limbconst || other.binary_basis_limbs[3].element.is_constant();
713
20
            limbconst = limbconst || other.prime_basis_limb.is_constant();
714
20
            limbconst =
715
20
                limbconst ||
716
20
                (prime_basis_limb.witness_index ==
717
20
                 other.prime_basis_limb.witness_index); // We are checking if this is and identical element, so we
718
                                                        // need to compare the actual indices, not normalized ones
719
20
            if (!limbconst) {
720
20
                std::pair<uint32_t, bb::fr> x0{ result.binary_basis_limbs[0].element.witness_index,
721
20
                                                binary_basis_limbs[0].element.multiplicative_constant };
722
20
                std::pair<uint32_t, bb::fr> x1{ result.binary_basis_limbs[1].element.witness_index,
723
20
                                                binary_basis_limbs[1].element.multiplicative_constant };
724
20
                std::pair<uint32_t, bb::fr> x2{ result.binary_basis_limbs[2].element.witness_index,
725
20
                                                binary_basis_limbs[2].element.multiplicative_constant };
726
20
                std::pair<uint32_t, bb::fr> x3{ result.binary_basis_limbs[3].element.witness_index,
727
20
                                                binary_basis_limbs[3].element.multiplicative_constant };
728
20
                std::pair<uint32_t, bb::fr> y0{ other.binary_basis_limbs[0].element.witness_index,
729
20
                                                other.binary_basis_limbs[0].element.multiplicative_constant };
730
20
                std::pair<uint32_t, bb::fr> y1{ other.binary_basis_limbs[1].element.witness_index,
731
20
                                                other.binary_basis_limbs[1].element.multiplicative_constant };
732
20
                std::pair<uint32_t, bb::fr> y2{ other.binary_basis_limbs[2].element.witness_index,
733
20
                                                other.binary_basis_limbs[2].element.multiplicative_constant };
734
20
                std::pair<uint32_t, bb::fr> y3{ other.binary_basis_limbs[3].element.witness_index,
735
20
                                                other.binary_basis_limbs[3].element.multiplicative_constant };
736
20
                bb::fr c0(result.binary_basis_limbs[0].element.additive_constant -
737
20
                          other.binary_basis_limbs[0].element.additive_constant);
738
20
                bb::fr c1(result.binary_basis_limbs[1].element.additive_constant -
739
20
                          other.binary_basis_limbs[1].element.additive_constant);
740
20
                bb::fr c2(result.binary_basis_limbs[2].element.additive_constant -
741
20
                          other.binary_basis_limbs[2].element.additive_constant);
742
20
                bb::fr c3(result.binary_basis_limbs[3].element.additive_constant -
743
20
                          other.binary_basis_limbs[3].element.additive_constant);
744
745
20
                uint32_t xp(prime_basis_limb.witness_index);
746
20
                uint32_t yp(other.prime_basis_limb.witness_index);
747
20
                bb::fr cp(prime_basis_limb.additive_constant - other.prime_basis_limb.additive_constant);
748
20
                uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
749
20
                cp += bb::fr(constant_to_add_mod_p.lo);
750
751
20
                const auto output_witnesses = ctx->evaluate_non_native_field_subtraction(
752
20
                    { x0, y0, c0 }, { x1, y1, c1 }, { x2, y2, c2 }, { x3, y3, c3 }, { xp, yp, cp });
753
754
20
                result.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[0]);
755
20
                result.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[1]);
756
20
                result.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[2]);
757
20
                result.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(ctx, output_witnesses[3]);
758
20
                result.prime_basis_limb = field_t<Builder>::from_witness_index(ctx, output_witnesses[4]);
759
760
20
                result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
761
20
                return result;
762
20
            }
763
20
        }
764
20
    }
765
766
0
    result.binary_basis_limbs[0].element -= other.binary_basis_limbs[0].element;
767
0
    result.binary_basis_limbs[1].element -= other.binary_basis_limbs[1].element;
768
0
    result.binary_basis_limbs[2].element -= other.binary_basis_limbs[2].element;
769
0
    result.binary_basis_limbs[3].element -= other.binary_basis_limbs[3].element;
770
771
    /**
772
     * Compute the prime basis limb of the result
773
     **/
774
0
    uint512_t constant_to_add_mod_p = (constant_to_add) % prime_basis.modulus;
775
0
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
776
0
    result.prime_basis_limb = prime_basis_limb + prime_basis_to_add;
777
0
    result.prime_basis_limb -= other.prime_basis_limb;
778
0
    return result;
779
20
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEmiERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEmiERKS9_
780
781
/**
782
 * Evaluate a non-native field multiplication: (a * b = c mod p) where p == target_basis.modulus
783
 *
784
 * We compute quotient term `q` and remainder `c` and evaluate that:
785
 *
786
 * a * b - q * p - c = 0 mod modulus_u512 (binary basis modulus, currently 2**272)
787
 * a * b - q * p - c = 0 mod circuit modulus
788
 **/
789
template <typename Builder, typename T>
790
bigfield<Builder, T> bigfield<Builder, T>::operator*(const bigfield& other) const
791
218k
{
792
    // First we do basic reduction checks of individual elements
793
218k
    reduction_check();
794
218k
    other.reduction_check();
795
218k
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
218k
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
218k
    bigfield remainder;
799
218k
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
218k
    if (is_constant() && other.is_constant()) {
802
4.13k
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
4.13k
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
4.13k
        return remainder;
805
214k
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
214k
        auto [reduction_required, num_quotient_bits] =
813
214k
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
214k
        if (reduction_required) {
815
1
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
1
            } else {
818
1
                other.self_reduce();
819
1
            }
820
1
            return (*this).operator*(other);
821
1
        }
822
214k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
214k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
214k
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
214k
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
214k
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
214k
    return remainder;
831
218k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEmlERKS6_
Line
Count
Source
791
212k
{
792
    // First we do basic reduction checks of individual elements
793
212k
    reduction_check();
794
212k
    other.reduction_check();
795
212k
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
212k
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
212k
    bigfield remainder;
799
212k
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
212k
    if (is_constant() && other.is_constant()) {
802
4.12k
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
4.12k
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
4.12k
        return remainder;
805
208k
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
208k
        auto [reduction_required, num_quotient_bits] =
813
208k
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
208k
        if (reduction_required) {
815
1
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
1
            } else {
818
1
                other.self_reduce();
819
1
            }
820
1
            return (*this).operator*(other);
821
1
        }
822
208k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
208k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
208k
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
208k
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
208k
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
208k
    return remainder;
831
212k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEmlERKS6_
Line
Count
Source
791
38
{
792
    // First we do basic reduction checks of individual elements
793
38
    reduction_check();
794
38
    other.reduction_check();
795
38
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
38
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
38
    bigfield remainder;
799
38
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
38
    if (is_constant() && other.is_constant()) {
802
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
0
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
0
        return remainder;
805
38
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
38
        auto [reduction_required, num_quotient_bits] =
813
38
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
38
        if (reduction_required) {
815
0
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
0
            } else {
818
0
                other.self_reduce();
819
0
            }
820
0
            return (*this).operator*(other);
821
0
        }
822
38
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
38
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
38
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
38
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
38
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
38
    return remainder;
831
38
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEmlERKS8_
Line
Count
Source
791
20
{
792
    // First we do basic reduction checks of individual elements
793
20
    reduction_check();
794
20
    other.reduction_check();
795
20
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
20
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
20
    bigfield remainder;
799
20
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
20
    if (is_constant() && other.is_constant()) {
802
4
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
4
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
4
        return remainder;
805
16
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
16
        auto [reduction_required, num_quotient_bits] =
813
16
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
16
        if (reduction_required) {
815
0
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
0
            } else {
818
0
                other.self_reduce();
819
0
            }
820
0
            return (*this).operator*(other);
821
0
        }
822
16
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
16
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
16
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
16
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
16
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
16
    return remainder;
831
20
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EmlERKS7_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEmlERKS7_
Line
Count
Source
791
246
{
792
    // First we do basic reduction checks of individual elements
793
246
    reduction_check();
794
246
    other.reduction_check();
795
246
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
246
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
246
    bigfield remainder;
799
246
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
246
    if (is_constant() && other.is_constant()) {
802
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
0
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
0
        return remainder;
805
246
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
246
        auto [reduction_required, num_quotient_bits] =
813
246
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
246
        if (reduction_required) {
815
0
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
0
            } else {
818
0
                other.self_reduce();
819
0
            }
820
0
            return (*this).operator*(other);
821
0
        }
822
246
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
246
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
246
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
246
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
246
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
246
    return remainder;
831
246
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEmlERKS7_
Line
Count
Source
791
1
{
792
    // First we do basic reduction checks of individual elements
793
1
    reduction_check();
794
1
    other.reduction_check();
795
1
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
1
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
1
    bigfield remainder;
799
1
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
1
    if (is_constant() && other.is_constant()) {
802
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
0
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
0
        return remainder;
805
1
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
1
        auto [reduction_required, num_quotient_bits] =
813
1
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
1
        if (reduction_required) {
815
0
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
0
            } else {
818
0
                other.self_reduce();
819
0
            }
820
0
            return (*this).operator*(other);
821
0
        }
822
1
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
1
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
1
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
1
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
1
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
1
    return remainder;
831
1
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEmlERKS9_
Line
Count
Source
791
5.90k
{
792
    // First we do basic reduction checks of individual elements
793
5.90k
    reduction_check();
794
5.90k
    other.reduction_check();
795
5.90k
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
5.90k
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
5.90k
    bigfield remainder;
799
5.90k
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
5.90k
    if (is_constant() && other.is_constant()) {
802
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
0
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
0
        return remainder;
805
5.90k
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
5.90k
        auto [reduction_required, num_quotient_bits] =
813
5.90k
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
5.90k
        if (reduction_required) {
815
0
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
0
            } else {
818
0
                other.self_reduce();
819
0
            }
820
0
            return (*this).operator*(other);
821
0
        }
822
5.90k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
5.90k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
5.90k
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
5.90k
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
5.90k
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
5.90k
    return remainder;
831
5.90k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEmlERKS9_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEmlERKS7_
Line
Count
Source
791
45
{
792
    // First we do basic reduction checks of individual elements
793
45
    reduction_check();
794
45
    other.reduction_check();
795
45
    Builder* ctx = context ? context : other.context;
796
    // Now we can actually compute the quotient and remainder values
797
45
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, other, {});
798
45
    bigfield remainder;
799
45
    bigfield quotient;
800
    // If operands are constant, define result as a constant value and return
801
45
    if (is_constant() && other.is_constant()) {
802
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
803
0
        remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
804
0
        return remainder;
805
45
    } else {
806
        // when writing a*b = q*p + r we wish to enforce r<2^s for smallest s such that p<2^s
807
        // hence the second constructor call is with can_overflow=false. This will allow using r in more additions
808
        // mod 2^t without needing to apply the mod, where t=4*NUM_LIMB_BITS
809
810
        // Check if the product overflows CRT or the quotient can't be contained in a range proof and reduce
811
        // accordingly
812
45
        auto [reduction_required, num_quotient_bits] =
813
45
            get_quotient_reduction_info({ get_maximum_value() }, { other.get_maximum_value() }, {});
814
45
        if (reduction_required) {
815
0
            if (get_maximum_value() > other.get_maximum_value()) {
816
0
                self_reduce();
817
0
            } else {
818
0
                other.self_reduce();
819
0
            }
820
0
            return (*this).operator*(other);
821
0
        }
822
45
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
823
45
        remainder = create_from_u512_as_witness(ctx, remainder_value);
824
45
    };
825
826
    // Call `evaluate_multiply_add` to validate the correctness of our computed quotient and remainder
827
45
    unsafe_evaluate_multiply_add(*this, other, {}, quotient, { remainder });
828
829
45
    remainder.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
830
45
    return remainder;
831
45
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEmlERKS7_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEmlERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEmlERKS9_
832
833
/**
834
 * Division operator. Create constraints for b!=0 by default. If you need a variant
835
 *without the zero check,  use div_without_denominator_check.
836
 *
837
 * To evaluate (a / b = c mod p), we instead evaluate (c * b = a mod p).
838
 **/
839
template <typename Builder, typename T>
840
bigfield<Builder, T> bigfield<Builder, T>::operator/(const bigfield& other) const
841
4.95k
{
842
843
4.95k
    return internal_div({ *this }, other, true);
844
4.95k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEdvERKS6_
Line
Count
Source
841
4.93k
{
842
843
4.93k
    return internal_div({ *this }, other, true);
844
4.93k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEdvERKS6_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEdvERKS8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EdvERKS7_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEdvERKS7_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEdvERKS7_
Line
Count
Source
841
12
{
842
843
12
    return internal_div({ *this }, other, true);
844
12
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEdvERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEdvERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEdvERKS7_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEdvERKS7_
Line
Count
Source
841
8
{
842
843
8
    return internal_div({ *this }, other, true);
844
8
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEdvERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEdvERKS9_
845
/**
846
 * @brief Create constraints for summing these terms
847
 *
848
 * @tparam Builder
849
 * @tparam T
850
 * @param terms
851
 * @return The sum of terms
852
 */
853
template <typename Builder, typename T>
854
bigfield<Builder, T> bigfield<Builder, T>::sum(const std::vector<bigfield>& terms)
855
0
{
856
0
    ASSERT(terms.size() > 0);
857
858
0
    if (terms.size() == 1) {
859
0
        return terms[0];
860
0
    }
861
862
0
    bigfield acc = terms[0];
863
0
    for (size_t i = 1; i < (terms.size() + 1) / 2; i++) {
864
0
        acc = acc.add_two(terms[2 * i - 1], terms[2 * i]);
865
0
    }
866
0
    if ((terms.size() & 1) == 0) {
867
0
        acc += terms[terms.size() - 1];
868
0
    }
869
0
    return acc;
870
0
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3sumERKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3sumERKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3sumERKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3sumERKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE3sumERKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE3sumERKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE3sumERKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE3sumERKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE3sumERKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE3sumERKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE3sumERKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE3sumERKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3sumERKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3sumERKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3sumERKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3sumERKSt6vectorIS7_SaIS7_EE
871
872
/**
873
 * Division of a sum with an optional check if divisor is zero. Should not be used outside of class.
874
 *
875
 * @param numerators Vector of numerators
876
 * @param denominator Denominator
877
 * @param check_for_zero If the zero check should be enabled
878
 *
879
 * @return The result of division
880
 * */
881
template <typename Builder, typename T>
882
bigfield<Builder, T> bigfield<Builder, T>::internal_div(const std::vector<bigfield>& numerators,
883
                                                        const bigfield& denominator,
884
                                                        bool check_for_zero)
885
118k
{
886
118k
    if (numerators.size() == 0) {
887
1
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
1
    }
889
890
118k
    denominator.reduction_check();
891
118k
    Builder* ctx = denominator.context;
892
118k
    uint512_t numerator_values(0);
893
118k
    bool numerator_constant = true;
894
118k
    OriginTag tag = denominator.get_origin_tag();
895
165k
    for (const auto& numerator_element : numerators) {
896
165k
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
165k
        numerator_element.reduction_check();
898
165k
        numerator_values += numerator_element.get_value();
899
165k
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
165k
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
165k
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
118k
    const uint1024_t left = uint1024_t(numerator_values);
906
118k
    const uint1024_t right = uint1024_t(denominator.get_value());
907
118k
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
118k
    uint512_t inverse_value(0);
910
118k
    if (right.lo != uint512_t(0)) {
911
118k
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
118k
    }
913
118k
    uint1024_t inverse_1024(inverse_value);
914
118k
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
118k
    const uint1024_t quotient_1024 =
917
118k
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
118k
    const uint512_t quotient_value = quotient_1024.lo;
919
920
118k
    bigfield inverse;
921
118k
    bigfield quotient;
922
118k
    if (numerator_constant && denominator.is_constant()) {
923
76
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
76
        inverse.set_origin_tag(tag);
925
76
        return inverse;
926
118k
    } else {
927
        // We only add the check if the result is non-constant
928
118k
        std::vector<uint1024_t> numerator_max;
929
165k
        for (const auto& n : numerators) {
930
165k
            numerator_max.push_back(n.get_maximum_value());
931
165k
        }
932
933
118k
        auto [reduction_required, num_quotient_bits] =
934
118k
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
118k
                                        { denominator.get_maximum_value() },
936
118k
                                        { unreduced_zero() },
937
118k
                                        numerator_max);
938
118k
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
118k
        if (check_for_zero) {
945
4.88k
            denominator.assert_is_not_equal(zero());
946
4.88k
        }
947
948
118k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
118k
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
118k
    }
951
952
118k
    inverse.set_origin_tag(tag);
953
118k
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
118k
    return inverse;
955
118k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE12internal_divERKSt6vectorIS6_SaIS6_EERKS6_b
Line
Count
Source
885
106k
{
886
106k
    if (numerators.size() == 0) {
887
1
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
1
    }
889
890
106k
    denominator.reduction_check();
891
106k
    Builder* ctx = denominator.context;
892
106k
    uint512_t numerator_values(0);
893
106k
    bool numerator_constant = true;
894
106k
    OriginTag tag = denominator.get_origin_tag();
895
153k
    for (const auto& numerator_element : numerators) {
896
153k
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
153k
        numerator_element.reduction_check();
898
153k
        numerator_values += numerator_element.get_value();
899
153k
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
153k
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
153k
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
106k
    const uint1024_t left = uint1024_t(numerator_values);
906
106k
    const uint1024_t right = uint1024_t(denominator.get_value());
907
106k
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
106k
    uint512_t inverse_value(0);
910
106k
    if (right.lo != uint512_t(0)) {
911
106k
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
106k
    }
913
106k
    uint1024_t inverse_1024(inverse_value);
914
106k
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
106k
    const uint1024_t quotient_1024 =
917
106k
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
106k
    const uint512_t quotient_value = quotient_1024.lo;
919
920
106k
    bigfield inverse;
921
106k
    bigfield quotient;
922
106k
    if (numerator_constant && denominator.is_constant()) {
923
76
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
76
        inverse.set_origin_tag(tag);
925
76
        return inverse;
926
105k
    } else {
927
        // We only add the check if the result is non-constant
928
105k
        std::vector<uint1024_t> numerator_max;
929
153k
        for (const auto& n : numerators) {
930
153k
            numerator_max.push_back(n.get_maximum_value());
931
153k
        }
932
933
105k
        auto [reduction_required, num_quotient_bits] =
934
105k
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
105k
                                        { denominator.get_maximum_value() },
936
105k
                                        { unreduced_zero() },
937
105k
                                        numerator_max);
938
105k
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
105k
        if (check_for_zero) {
945
4.86k
            denominator.assert_is_not_equal(zero());
946
4.86k
        }
947
948
105k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
105k
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
105k
    }
951
952
105k
    inverse.set_origin_tag(tag);
953
105k
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
105k
    return inverse;
955
106k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE12internal_divERKSt6vectorIS6_SaIS6_EERKS6_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE12internal_divERKSt6vectorIS8_SaIS8_EERKS8_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E12internal_divERKSt6vectorIS7_SaIS7_EERKS7_b
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE12internal_divERKSt6vectorIS7_SaIS7_EERKS7_b
Line
Count
Source
885
488
{
886
488
    if (numerators.size() == 0) {
887
0
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
0
    }
889
890
488
    denominator.reduction_check();
891
488
    Builder* ctx = denominator.context;
892
488
    uint512_t numerator_values(0);
893
488
    bool numerator_constant = true;
894
488
    OriginTag tag = denominator.get_origin_tag();
895
494
    for (const auto& numerator_element : numerators) {
896
494
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
494
        numerator_element.reduction_check();
898
494
        numerator_values += numerator_element.get_value();
899
494
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
494
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
494
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
488
    const uint1024_t left = uint1024_t(numerator_values);
906
488
    const uint1024_t right = uint1024_t(denominator.get_value());
907
488
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
488
    uint512_t inverse_value(0);
910
488
    if (right.lo != uint512_t(0)) {
911
488
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
488
    }
913
488
    uint1024_t inverse_1024(inverse_value);
914
488
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
488
    const uint1024_t quotient_1024 =
917
488
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
488
    const uint512_t quotient_value = quotient_1024.lo;
919
920
488
    bigfield inverse;
921
488
    bigfield quotient;
922
488
    if (numerator_constant && denominator.is_constant()) {
923
0
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
0
        inverse.set_origin_tag(tag);
925
0
        return inverse;
926
488
    } else {
927
        // We only add the check if the result is non-constant
928
488
        std::vector<uint1024_t> numerator_max;
929
494
        for (const auto& n : numerators) {
930
494
            numerator_max.push_back(n.get_maximum_value());
931
494
        }
932
933
488
        auto [reduction_required, num_quotient_bits] =
934
488
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
488
                                        { denominator.get_maximum_value() },
936
488
                                        { unreduced_zero() },
937
488
                                        numerator_max);
938
488
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
488
        if (check_for_zero) {
945
0
            denominator.assert_is_not_equal(zero());
946
0
        }
947
948
488
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
488
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
488
    }
951
952
488
    inverse.set_origin_tag(tag);
953
488
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
488
    return inverse;
955
488
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE12internal_divERKSt6vectorIS7_SaIS7_EERKS7_b
Line
Count
Source
885
14
{
886
14
    if (numerators.size() == 0) {
887
0
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
0
    }
889
890
14
    denominator.reduction_check();
891
14
    Builder* ctx = denominator.context;
892
14
    uint512_t numerator_values(0);
893
14
    bool numerator_constant = true;
894
14
    OriginTag tag = denominator.get_origin_tag();
895
14
    for (const auto& numerator_element : numerators) {
896
14
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
14
        numerator_element.reduction_check();
898
14
        numerator_values += numerator_element.get_value();
899
14
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
14
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
14
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
14
    const uint1024_t left = uint1024_t(numerator_values);
906
14
    const uint1024_t right = uint1024_t(denominator.get_value());
907
14
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
14
    uint512_t inverse_value(0);
910
14
    if (right.lo != uint512_t(0)) {
911
14
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
14
    }
913
14
    uint1024_t inverse_1024(inverse_value);
914
14
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
14
    const uint1024_t quotient_1024 =
917
14
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
14
    const uint512_t quotient_value = quotient_1024.lo;
919
920
14
    bigfield inverse;
921
14
    bigfield quotient;
922
14
    if (numerator_constant && denominator.is_constant()) {
923
0
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
0
        inverse.set_origin_tag(tag);
925
0
        return inverse;
926
14
    } else {
927
        // We only add the check if the result is non-constant
928
14
        std::vector<uint1024_t> numerator_max;
929
14
        for (const auto& n : numerators) {
930
14
            numerator_max.push_back(n.get_maximum_value());
931
14
        }
932
933
14
        auto [reduction_required, num_quotient_bits] =
934
14
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
14
                                        { denominator.get_maximum_value() },
936
14
                                        { unreduced_zero() },
937
14
                                        numerator_max);
938
14
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
14
        if (check_for_zero) {
945
12
            denominator.assert_is_not_equal(zero());
946
12
        }
947
948
14
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
14
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
14
    }
951
952
14
    inverse.set_origin_tag(tag);
953
14
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
14
    return inverse;
955
14
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE12internal_divERKSt6vectorIS9_SaIS9_EERKS9_b
Line
Count
Source
885
10.9k
{
886
10.9k
    if (numerators.size() == 0) {
887
0
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
0
    }
889
890
10.9k
    denominator.reduction_check();
891
10.9k
    Builder* ctx = denominator.context;
892
10.9k
    uint512_t numerator_values(0);
893
10.9k
    bool numerator_constant = true;
894
10.9k
    OriginTag tag = denominator.get_origin_tag();
895
11.0k
    for (const auto& numerator_element : numerators) {
896
11.0k
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
11.0k
        numerator_element.reduction_check();
898
11.0k
        numerator_values += numerator_element.get_value();
899
11.0k
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
11.0k
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
11.0k
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
10.9k
    const uint1024_t left = uint1024_t(numerator_values);
906
10.9k
    const uint1024_t right = uint1024_t(denominator.get_value());
907
10.9k
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
10.9k
    uint512_t inverse_value(0);
910
10.9k
    if (right.lo != uint512_t(0)) {
911
10.9k
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
10.9k
    }
913
10.9k
    uint1024_t inverse_1024(inverse_value);
914
10.9k
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
10.9k
    const uint1024_t quotient_1024 =
917
10.9k
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
10.9k
    const uint512_t quotient_value = quotient_1024.lo;
919
920
10.9k
    bigfield inverse;
921
10.9k
    bigfield quotient;
922
10.9k
    if (numerator_constant && denominator.is_constant()) {
923
0
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
0
        inverse.set_origin_tag(tag);
925
0
        return inverse;
926
10.9k
    } else {
927
        // We only add the check if the result is non-constant
928
10.9k
        std::vector<uint1024_t> numerator_max;
929
11.0k
        for (const auto& n : numerators) {
930
11.0k
            numerator_max.push_back(n.get_maximum_value());
931
11.0k
        }
932
933
10.9k
        auto [reduction_required, num_quotient_bits] =
934
10.9k
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
10.9k
                                        { denominator.get_maximum_value() },
936
10.9k
                                        { unreduced_zero() },
937
10.9k
                                        numerator_max);
938
10.9k
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
10.9k
        if (check_for_zero) {
945
0
            denominator.assert_is_not_equal(zero());
946
0
        }
947
948
10.9k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
10.9k
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
10.9k
    }
951
952
10.9k
    inverse.set_origin_tag(tag);
953
10.9k
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
10.9k
    return inverse;
955
10.9k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE12internal_divERKSt6vectorIS9_SaIS9_EERKS9_b
Line
Count
Source
885
288
{
886
288
    if (numerators.size() == 0) {
887
0
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
0
    }
889
890
288
    denominator.reduction_check();
891
288
    Builder* ctx = denominator.context;
892
288
    uint512_t numerator_values(0);
893
288
    bool numerator_constant = true;
894
288
    OriginTag tag = denominator.get_origin_tag();
895
288
    for (const auto& numerator_element : numerators) {
896
288
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
288
        numerator_element.reduction_check();
898
288
        numerator_values += numerator_element.get_value();
899
288
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
288
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
288
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
288
    const uint1024_t left = uint1024_t(numerator_values);
906
288
    const uint1024_t right = uint1024_t(denominator.get_value());
907
288
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
288
    uint512_t inverse_value(0);
910
288
    if (right.lo != uint512_t(0)) {
911
288
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
288
    }
913
288
    uint1024_t inverse_1024(inverse_value);
914
288
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
288
    const uint1024_t quotient_1024 =
917
288
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
288
    const uint512_t quotient_value = quotient_1024.lo;
919
920
288
    bigfield inverse;
921
288
    bigfield quotient;
922
288
    if (numerator_constant && denominator.is_constant()) {
923
0
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
0
        inverse.set_origin_tag(tag);
925
0
        return inverse;
926
288
    } else {
927
        // We only add the check if the result is non-constant
928
288
        std::vector<uint1024_t> numerator_max;
929
288
        for (const auto& n : numerators) {
930
288
            numerator_max.push_back(n.get_maximum_value());
931
288
        }
932
933
288
        auto [reduction_required, num_quotient_bits] =
934
288
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
288
                                        { denominator.get_maximum_value() },
936
288
                                        { unreduced_zero() },
937
288
                                        numerator_max);
938
288
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
288
        if (check_for_zero) {
945
0
            denominator.assert_is_not_equal(zero());
946
0
        }
947
948
288
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
288
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
288
    }
951
952
288
    inverse.set_origin_tag(tag);
953
288
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
288
    return inverse;
955
288
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE12internal_divERKSt6vectorIS7_SaIS7_EERKS7_b
Line
Count
Source
885
670
{
886
670
    if (numerators.size() == 0) {
887
0
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
0
    }
889
890
670
    denominator.reduction_check();
891
670
    Builder* ctx = denominator.context;
892
670
    uint512_t numerator_values(0);
893
670
    bool numerator_constant = true;
894
670
    OriginTag tag = denominator.get_origin_tag();
895
685
    for (const auto& numerator_element : numerators) {
896
685
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
685
        numerator_element.reduction_check();
898
685
        numerator_values += numerator_element.get_value();
899
685
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
685
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
685
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
670
    const uint1024_t left = uint1024_t(numerator_values);
906
670
    const uint1024_t right = uint1024_t(denominator.get_value());
907
670
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
670
    uint512_t inverse_value(0);
910
670
    if (right.lo != uint512_t(0)) {
911
670
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
670
    }
913
670
    uint1024_t inverse_1024(inverse_value);
914
670
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
670
    const uint1024_t quotient_1024 =
917
670
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
670
    const uint512_t quotient_value = quotient_1024.lo;
919
920
670
    bigfield inverse;
921
670
    bigfield quotient;
922
670
    if (numerator_constant && denominator.is_constant()) {
923
0
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
0
        inverse.set_origin_tag(tag);
925
0
        return inverse;
926
670
    } else {
927
        // We only add the check if the result is non-constant
928
670
        std::vector<uint1024_t> numerator_max;
929
685
        for (const auto& n : numerators) {
930
685
            numerator_max.push_back(n.get_maximum_value());
931
685
        }
932
933
670
        auto [reduction_required, num_quotient_bits] =
934
670
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
670
                                        { denominator.get_maximum_value() },
936
670
                                        { unreduced_zero() },
937
670
                                        numerator_max);
938
670
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
670
        if (check_for_zero) {
945
0
            denominator.assert_is_not_equal(zero());
946
0
        }
947
948
670
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
670
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
670
    }
951
952
670
    inverse.set_origin_tag(tag);
953
670
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
670
    return inverse;
955
670
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE12internal_divERKSt6vectorIS7_SaIS7_EERKS7_b
Line
Count
Source
885
10
{
886
10
    if (numerators.size() == 0) {
887
0
        return bigfield<Builder, T>(denominator.get_context(), uint256_t(0));
888
0
    }
889
890
10
    denominator.reduction_check();
891
10
    Builder* ctx = denominator.context;
892
10
    uint512_t numerator_values(0);
893
10
    bool numerator_constant = true;
894
10
    OriginTag tag = denominator.get_origin_tag();
895
10
    for (const auto& numerator_element : numerators) {
896
10
        ctx = (ctx == nullptr) ? numerator_element.get_context() : ctx;
897
10
        numerator_element.reduction_check();
898
10
        numerator_values += numerator_element.get_value();
899
10
        numerator_constant = numerator_constant && (numerator_element.is_constant());
900
10
        tag = OriginTag(tag, numerator_element.get_origin_tag());
901
10
    }
902
903
    // a / b = c
904
    // => c * b = a mod p
905
10
    const uint1024_t left = uint1024_t(numerator_values);
906
10
    const uint1024_t right = uint1024_t(denominator.get_value());
907
10
    const uint1024_t modulus(target_basis.modulus);
908
    // We don't want to trigger the uint assert
909
10
    uint512_t inverse_value(0);
910
10
    if (right.lo != uint512_t(0)) {
911
10
        inverse_value = right.lo.invmod(target_basis.modulus).lo;
912
10
    }
913
10
    uint1024_t inverse_1024(inverse_value);
914
10
    inverse_value = ((left * inverse_1024) % modulus).lo;
915
916
10
    const uint1024_t quotient_1024 =
917
10
        (uint1024_t(inverse_value) * right + unreduced_zero().get_value() - left) / modulus;
918
10
    const uint512_t quotient_value = quotient_1024.lo;
919
920
10
    bigfield inverse;
921
10
    bigfield quotient;
922
10
    if (numerator_constant && denominator.is_constant()) {
923
0
        inverse = bigfield(ctx, uint256_t(inverse_value));
924
0
        inverse.set_origin_tag(tag);
925
0
        return inverse;
926
10
    } else {
927
        // We only add the check if the result is non-constant
928
10
        std::vector<uint1024_t> numerator_max;
929
10
        for (const auto& n : numerators) {
930
10
            numerator_max.push_back(n.get_maximum_value());
931
10
        }
932
933
10
        auto [reduction_required, num_quotient_bits] =
934
10
            get_quotient_reduction_info({ static_cast<uint512_t>(DEFAULT_MAXIMUM_REMAINDER) },
935
10
                                        { denominator.get_maximum_value() },
936
10
                                        { unreduced_zero() },
937
10
                                        numerator_max);
938
10
        if (reduction_required) {
939
940
0
            denominator.self_reduce();
941
0
            return internal_div(numerators, denominator, check_for_zero);
942
0
        }
943
        // We do this after the quotient check, since this creates gates and we don't want to do this twice
944
10
        if (check_for_zero) {
945
8
            denominator.assert_is_not_equal(zero());
946
8
        }
947
948
10
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
949
10
        inverse = create_from_u512_as_witness(ctx, inverse_value);
950
10
    }
951
952
10
    inverse.set_origin_tag(tag);
953
10
    unsafe_evaluate_multiply_add(denominator, inverse, { unreduced_zero() }, quotient, numerators);
954
10
    return inverse;
955
10
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE12internal_divERKSt6vectorIS9_SaIS9_EERKS9_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE12internal_divERKSt6vectorIS9_SaIS9_EERKS9_b
956
957
/**
958
 * Div method without constraining denominator!=0.
959
 *
960
 * Similar to operator/ but numerator can be linear sum of multiple elements
961
 *
962
 **/
963
template <typename Builder, typename T>
964
bigfield<Builder, T> bigfield<Builder, T>::div_without_denominator_check(const std::vector<bigfield>& numerators,
965
                                                                         const bigfield& denominator)
966
113k
{
967
113k
    return internal_div(numerators, denominator, false);
968
113k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE29div_without_denominator_checkERKSt6vectorIS6_SaIS6_EERKS6_
Line
Count
Source
966
101k
{
967
101k
    return internal_div(numerators, denominator, false);
968
101k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE29div_without_denominator_checkERKSt6vectorIS6_SaIS6_EERKS6_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE29div_without_denominator_checkERKSt6vectorIS8_SaIS8_EERKS8_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E29div_without_denominator_checkERKSt6vectorIS7_SaIS7_EERKS7_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE29div_without_denominator_checkERKSt6vectorIS7_SaIS7_EERKS7_
Line
Count
Source
966
488
{
967
488
    return internal_div(numerators, denominator, false);
968
488
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE29div_without_denominator_checkERKSt6vectorIS7_SaIS7_EERKS7_
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE29div_without_denominator_checkERKSt6vectorIS9_SaIS9_EERKS9_
Line
Count
Source
966
10.9k
{
967
10.9k
    return internal_div(numerators, denominator, false);
968
10.9k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE29div_without_denominator_checkERKSt6vectorIS9_SaIS9_EERKS9_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE29div_without_denominator_checkERKSt6vectorIS7_SaIS7_EERKS7_
Line
Count
Source
966
670
{
967
670
    return internal_div(numerators, denominator, false);
968
670
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE29div_without_denominator_checkERKSt6vectorIS7_SaIS7_EERKS7_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE29div_without_denominator_checkERKSt6vectorIS9_SaIS9_EERKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE29div_without_denominator_checkERKSt6vectorIS9_SaIS9_EERKS9_
969
970
template <typename Builder, typename T>
971
bigfield<Builder, T> bigfield<Builder, T>::div_without_denominator_check(const bigfield& denominator)
972
292
{
973
292
    return internal_div({ *this }, denominator, false);
974
292
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE29div_without_denominator_checkERKS6_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE29div_without_denominator_checkERKS6_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE29div_without_denominator_checkERKS8_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E29div_without_denominator_checkERKS7_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE29div_without_denominator_checkERKS7_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE29div_without_denominator_checkERKS7_
Line
Count
Source
972
2
{
973
2
    return internal_div({ *this }, denominator, false);
974
2
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE29div_without_denominator_checkERKS9_
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE29div_without_denominator_checkERKS9_
Line
Count
Source
972
288
{
973
288
    return internal_div({ *this }, denominator, false);
974
288
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE29div_without_denominator_checkERKS7_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE29div_without_denominator_checkERKS7_
Line
Count
Source
972
2
{
973
2
    return internal_div({ *this }, denominator, false);
974
2
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE29div_without_denominator_checkERKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE29div_without_denominator_checkERKS9_
975
976
/**
977
 * Div method with constraints for denominator!=0.
978
 *
979
 * Similar to operator/ but numerator can be linear sum of multiple elements
980
 *
981
 * TODO: After we create a mechanism for easy updating of witnesses, create a test with proof check
982
 **/
983
template <typename Builder, typename T>
984
bigfield<Builder, T> bigfield<Builder, T>::div_check_denominator_nonzero(const std::vector<bigfield>& numerators,
985
                                                                         const bigfield& denominator)
986
1
{
987
1
    return internal_div(numerators, denominator, true);
988
1
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS6_SaIS6_EERKS6_
Line
Count
Source
986
1
{
987
1
    return internal_div(numerators, denominator, true);
988
1
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE29div_check_denominator_nonzeroERKSt6vectorIS6_SaIS6_EERKS6_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS8_SaIS8_EERKS8_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E29div_check_denominator_nonzeroERKSt6vectorIS7_SaIS7_EERKS7_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS7_SaIS7_EERKS7_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE29div_check_denominator_nonzeroERKSt6vectorIS7_SaIS7_EERKS7_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS9_SaIS9_EERKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE29div_check_denominator_nonzeroERKSt6vectorIS9_SaIS9_EERKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS7_SaIS7_EERKS7_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE29div_check_denominator_nonzeroERKSt6vectorIS7_SaIS7_EERKS7_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE29div_check_denominator_nonzeroERKSt6vectorIS9_SaIS9_EERKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE29div_check_denominator_nonzeroERKSt6vectorIS9_SaIS9_EERKS9_
989
/**
990
 * Compute a * a = c mod p
991
 *
992
 * Slightly cheaper than operator* for Standard
993
 **/
994
template <typename Builder, typename T> bigfield<Builder, T> bigfield<Builder, T>::sqr() const
995
3.50k
{
996
3.50k
    reduction_check();
997
3.50k
    Builder* ctx = context;
998
999
3.50k
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, *this, {});
1000
1001
3.50k
    bigfield remainder;
1002
3.50k
    bigfield quotient;
1003
3.50k
    if (is_constant()) {
1004
208
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1005
208
        return remainder;
1006
3.29k
    } else {
1007
1008
3.29k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1009
3.29k
            { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER });
1010
3.29k
        if (reduction_required) {
1011
1
            self_reduce();
1012
1
            return sqr();
1013
1
        }
1014
1015
3.29k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1016
3.29k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1017
3.29k
    };
1018
1019
3.29k
    unsafe_evaluate_square_add(*this, {}, quotient, remainder);
1020
3.29k
    remainder.set_origin_tag(get_origin_tag());
1021
3.29k
    return remainder;
1022
3.50k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3sqrEv
Line
Count
Source
995
3.20k
{
996
3.20k
    reduction_check();
997
3.20k
    Builder* ctx = context;
998
999
3.20k
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, *this, {});
1000
1001
3.20k
    bigfield remainder;
1002
3.20k
    bigfield quotient;
1003
3.20k
    if (is_constant()) {
1004
208
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1005
208
        return remainder;
1006
2.99k
    } else {
1007
1008
2.99k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1009
2.99k
            { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER });
1010
2.99k
        if (reduction_required) {
1011
1
            self_reduce();
1012
1
            return sqr();
1013
1
        }
1014
1015
2.99k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1016
2.99k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1017
2.99k
    };
1018
1019
2.99k
    unsafe_evaluate_square_add(*this, {}, quotient, remainder);
1020
2.99k
    remainder.set_origin_tag(get_origin_tag());
1021
2.99k
    return remainder;
1022
3.20k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3sqrEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3sqrEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3sqrEv
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE3sqrEv
Line
Count
Source
995
9
{
996
9
    reduction_check();
997
9
    Builder* ctx = context;
998
999
9
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, *this, {});
1000
1001
9
    bigfield remainder;
1002
9
    bigfield quotient;
1003
9
    if (is_constant()) {
1004
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1005
0
        return remainder;
1006
9
    } else {
1007
1008
9
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1009
9
            { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER });
1010
9
        if (reduction_required) {
1011
0
            self_reduce();
1012
0
            return sqr();
1013
0
        }
1014
1015
9
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1016
9
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1017
9
    };
1018
1019
9
    unsafe_evaluate_square_add(*this, {}, quotient, remainder);
1020
9
    remainder.set_origin_tag(get_origin_tag());
1021
9
    return remainder;
1022
9
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE3sqrEv
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE3sqrEv
Line
Count
Source
995
288
{
996
288
    reduction_check();
997
288
    Builder* ctx = context;
998
999
288
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, *this, {});
1000
1001
288
    bigfield remainder;
1002
288
    bigfield quotient;
1003
288
    if (is_constant()) {
1004
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1005
0
        return remainder;
1006
288
    } else {
1007
1008
288
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1009
288
            { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER });
1010
288
        if (reduction_required) {
1011
0
            self_reduce();
1012
0
            return sqr();
1013
0
        }
1014
1015
288
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1016
288
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1017
288
    };
1018
1019
288
    unsafe_evaluate_square_add(*this, {}, quotient, remainder);
1020
288
    remainder.set_origin_tag(get_origin_tag());
1021
288
    return remainder;
1022
288
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE3sqrEv
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE3sqrEv
Line
Count
Source
995
6
{
996
6
    reduction_check();
997
6
    Builder* ctx = context;
998
999
6
    const auto [quotient_value, remainder_value] = compute_quotient_remainder_values(*this, *this, {});
1000
1001
6
    bigfield remainder;
1002
6
    bigfield quotient;
1003
6
    if (is_constant()) {
1004
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1005
0
        return remainder;
1006
6
    } else {
1007
1008
6
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1009
6
            { get_maximum_value() }, { get_maximum_value() }, {}, { DEFAULT_MAXIMUM_REMAINDER });
1010
6
        if (reduction_required) {
1011
0
            self_reduce();
1012
0
            return sqr();
1013
0
        }
1014
1015
6
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1016
6
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1017
6
    };
1018
1019
6
    unsafe_evaluate_square_add(*this, {}, quotient, remainder);
1020
6
    remainder.set_origin_tag(get_origin_tag());
1021
6
    return remainder;
1022
6
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE3sqrEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE3sqrEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE3sqrEv
1023
1024
/**
1025
 * Compute a * a + ...to_add = b mod p
1026
 *
1027
 * We can chain multiple additions to a square/multiply with a single quotient/remainder.
1028
 *
1029
 * Chaining the additions here is cheaper than calling operator+ because we can combine some gates in
1030
 *`evaluate_multiply_add`
1031
 **/
1032
template <typename Builder, typename T>
1033
bigfield<Builder, T> bigfield<Builder, T>::sqradd(const std::vector<bigfield>& to_add) const
1034
377k
{
1035
377k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1036
0
    reduction_check();
1037
1038
0
    Builder* ctx = context;
1039
1040
0
    uint512_t add_values(0);
1041
0
    bool add_constant = true;
1042
723k
    for (const auto& add_element : to_add) {
1043
723k
        add_element.reduction_check();
1044
723k
        add_values += add_element.get_value();
1045
723k
        add_constant = add_constant && (add_element.is_constant());
1046
723k
    }
1047
1048
0
    const uint1024_t left(get_value());
1049
0
    const uint1024_t right(get_value());
1050
0
    const uint1024_t add_right(add_values);
1051
0
    const uint1024_t modulus(target_basis.modulus);
1052
1053
0
    bigfield remainder;
1054
0
    bigfield quotient;
1055
377k
    if (is_constant()) {
1056
2
        if (add_constant) {
1057
1058
2
            const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1059
2
            remainder = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1060
            // Merge tags
1061
2
            OriginTag new_tag = get_origin_tag();
1062
2
            for (auto& element : to_add) {
1063
2
                new_tag = OriginTag(new_tag, element.get_origin_tag());
1064
2
            }
1065
2
            remainder.set_origin_tag(new_tag);
1066
2
            return remainder;
1067
2
        } else {
1068
1069
0
            const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus);
1070
0
            std::vector<bigfield> new_to_add;
1071
0
            for (auto& add_element : to_add) {
1072
0
                new_to_add.push_back(add_element);
1073
0
            }
1074
1075
0
            new_to_add.push_back(bigfield(ctx, remainder_1024.lo.lo));
1076
0
            return sum(new_to_add);
1077
0
        }
1078
377k
    } else {
1079
1080
        // Check the quotient fits the range proof
1081
377k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1082
377k
            { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1083
1084
377k
        if (reduction_required) {
1085
1
            self_reduce();
1086
1
            return sqradd(to_add);
1087
1
        }
1088
377k
        const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1089
377k
        uint512_t quotient_value = quotient_1024.lo;
1090
377k
        uint256_t remainder_value = remainder_1024.lo.lo;
1091
1092
377k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1093
377k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1094
377k
    };
1095
377k
    OriginTag new_tag = get_origin_tag();
1096
723k
    for (auto& element : to_add) {
1097
723k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1098
723k
    }
1099
377k
    remainder.set_origin_tag(new_tag);
1100
377k
    unsafe_evaluate_square_add(*this, to_add, quotient, remainder);
1101
377k
    return remainder;
1102
0
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE6sqraddERKSt6vectorIS6_SaIS6_EE
Line
Count
Source
1034
354k
{
1035
354k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1036
354k
    reduction_check();
1037
1038
354k
    Builder* ctx = context;
1039
1040
354k
    uint512_t add_values(0);
1041
354k
    bool add_constant = true;
1042
682k
    for (const auto& add_element : to_add) {
1043
682k
        add_element.reduction_check();
1044
682k
        add_values += add_element.get_value();
1045
682k
        add_constant = add_constant && (add_element.is_constant());
1046
682k
    }
1047
1048
354k
    const uint1024_t left(get_value());
1049
354k
    const uint1024_t right(get_value());
1050
354k
    const uint1024_t add_right(add_values);
1051
354k
    const uint1024_t modulus(target_basis.modulus);
1052
1053
354k
    bigfield remainder;
1054
354k
    bigfield quotient;
1055
354k
    if (is_constant()) {
1056
2
        if (add_constant) {
1057
1058
2
            const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1059
2
            remainder = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1060
            // Merge tags
1061
2
            OriginTag new_tag = get_origin_tag();
1062
2
            for (auto& element : to_add) {
1063
2
                new_tag = OriginTag(new_tag, element.get_origin_tag());
1064
2
            }
1065
2
            remainder.set_origin_tag(new_tag);
1066
2
            return remainder;
1067
2
        } else {
1068
1069
0
            const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus);
1070
0
            std::vector<bigfield> new_to_add;
1071
0
            for (auto& add_element : to_add) {
1072
0
                new_to_add.push_back(add_element);
1073
0
            }
1074
1075
0
            new_to_add.push_back(bigfield(ctx, remainder_1024.lo.lo));
1076
0
            return sum(new_to_add);
1077
0
        }
1078
354k
    } else {
1079
1080
        // Check the quotient fits the range proof
1081
354k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1082
354k
            { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1083
1084
354k
        if (reduction_required) {
1085
1
            self_reduce();
1086
1
            return sqradd(to_add);
1087
1
        }
1088
354k
        const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1089
354k
        uint512_t quotient_value = quotient_1024.lo;
1090
354k
        uint256_t remainder_value = remainder_1024.lo.lo;
1091
1092
354k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1093
354k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1094
354k
    };
1095
354k
    OriginTag new_tag = get_origin_tag();
1096
682k
    for (auto& element : to_add) {
1097
682k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1098
682k
    }
1099
354k
    remainder.set_origin_tag(new_tag);
1100
354k
    unsafe_evaluate_square_add(*this, to_add, quotient, remainder);
1101
354k
    return remainder;
1102
354k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE6sqraddERKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE6sqraddERKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E6sqraddERKSt6vectorIS7_SaIS7_EE
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE6sqraddERKSt6vectorIS7_SaIS7_EE
Line
Count
Source
1034
1.00k
{
1035
1.00k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1036
1.00k
    reduction_check();
1037
1038
1.00k
    Builder* ctx = context;
1039
1040
1.00k
    uint512_t add_values(0);
1041
1.00k
    bool add_constant = true;
1042
1.69k
    for (const auto& add_element : to_add) {
1043
1.69k
        add_element.reduction_check();
1044
1.69k
        add_values += add_element.get_value();
1045
1.69k
        add_constant = add_constant && (add_element.is_constant());
1046
1.69k
    }
1047
1048
1.00k
    const uint1024_t left(get_value());
1049
1.00k
    const uint1024_t right(get_value());
1050
1.00k
    const uint1024_t add_right(add_values);
1051
1.00k
    const uint1024_t modulus(target_basis.modulus);
1052
1053
1.00k
    bigfield remainder;
1054
1.00k
    bigfield quotient;
1055
1.00k
    if (is_constant()) {
1056
0
        if (add_constant) {
1057
1058
0
            const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1059
0
            remainder = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1060
            // Merge tags
1061
0
            OriginTag new_tag = get_origin_tag();
1062
0
            for (auto& element : to_add) {
1063
0
                new_tag = OriginTag(new_tag, element.get_origin_tag());
1064
0
            }
1065
0
            remainder.set_origin_tag(new_tag);
1066
0
            return remainder;
1067
0
        } else {
1068
1069
0
            const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus);
1070
0
            std::vector<bigfield> new_to_add;
1071
0
            for (auto& add_element : to_add) {
1072
0
                new_to_add.push_back(add_element);
1073
0
            }
1074
1075
0
            new_to_add.push_back(bigfield(ctx, remainder_1024.lo.lo));
1076
0
            return sum(new_to_add);
1077
0
        }
1078
1.00k
    } else {
1079
1080
        // Check the quotient fits the range proof
1081
1.00k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1082
1.00k
            { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1083
1084
1.00k
        if (reduction_required) {
1085
0
            self_reduce();
1086
0
            return sqradd(to_add);
1087
0
        }
1088
1.00k
        const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1089
1.00k
        uint512_t quotient_value = quotient_1024.lo;
1090
1.00k
        uint256_t remainder_value = remainder_1024.lo.lo;
1091
1092
1.00k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1093
1.00k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1094
1.00k
    };
1095
1.00k
    OriginTag new_tag = get_origin_tag();
1096
1.69k
    for (auto& element : to_add) {
1097
1.69k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1098
1.69k
    }
1099
1.00k
    remainder.set_origin_tag(new_tag);
1100
1.00k
    unsafe_evaluate_square_add(*this, to_add, quotient, remainder);
1101
1.00k
    return remainder;
1102
1.00k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE6sqraddERKSt6vectorIS7_SaIS7_EE
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE6sqraddERKSt6vectorIS9_SaIS9_EE
Line
Count
Source
1034
20.5k
{
1035
20.5k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1036
20.5k
    reduction_check();
1037
1038
20.5k
    Builder* ctx = context;
1039
1040
20.5k
    uint512_t add_values(0);
1041
20.5k
    bool add_constant = true;
1042
36.4k
    for (const auto& add_element : to_add) {
1043
36.4k
        add_element.reduction_check();
1044
36.4k
        add_values += add_element.get_value();
1045
36.4k
        add_constant = add_constant && (add_element.is_constant());
1046
36.4k
    }
1047
1048
20.5k
    const uint1024_t left(get_value());
1049
20.5k
    const uint1024_t right(get_value());
1050
20.5k
    const uint1024_t add_right(add_values);
1051
20.5k
    const uint1024_t modulus(target_basis.modulus);
1052
1053
20.5k
    bigfield remainder;
1054
20.5k
    bigfield quotient;
1055
20.5k
    if (is_constant()) {
1056
0
        if (add_constant) {
1057
1058
0
            const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1059
0
            remainder = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1060
            // Merge tags
1061
0
            OriginTag new_tag = get_origin_tag();
1062
0
            for (auto& element : to_add) {
1063
0
                new_tag = OriginTag(new_tag, element.get_origin_tag());
1064
0
            }
1065
0
            remainder.set_origin_tag(new_tag);
1066
0
            return remainder;
1067
0
        } else {
1068
1069
0
            const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus);
1070
0
            std::vector<bigfield> new_to_add;
1071
0
            for (auto& add_element : to_add) {
1072
0
                new_to_add.push_back(add_element);
1073
0
            }
1074
1075
0
            new_to_add.push_back(bigfield(ctx, remainder_1024.lo.lo));
1076
0
            return sum(new_to_add);
1077
0
        }
1078
20.5k
    } else {
1079
1080
        // Check the quotient fits the range proof
1081
20.5k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1082
20.5k
            { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1083
1084
20.5k
        if (reduction_required) {
1085
0
            self_reduce();
1086
0
            return sqradd(to_add);
1087
0
        }
1088
20.5k
        const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1089
20.5k
        uint512_t quotient_value = quotient_1024.lo;
1090
20.5k
        uint256_t remainder_value = remainder_1024.lo.lo;
1091
1092
20.5k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1093
20.5k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1094
20.5k
    };
1095
20.5k
    OriginTag new_tag = get_origin_tag();
1096
36.4k
    for (auto& element : to_add) {
1097
36.4k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1098
36.4k
    }
1099
20.5k
    remainder.set_origin_tag(new_tag);
1100
20.5k
    unsafe_evaluate_square_add(*this, to_add, quotient, remainder);
1101
20.5k
    return remainder;
1102
20.5k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE6sqraddERKSt6vectorIS9_SaIS9_EE
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE6sqraddERKSt6vectorIS7_SaIS7_EE
Line
Count
Source
1034
1.30k
{
1035
1.30k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1036
1.30k
    reduction_check();
1037
1038
1.30k
    Builder* ctx = context;
1039
1040
1.30k
    uint512_t add_values(0);
1041
1.30k
    bool add_constant = true;
1042
2.60k
    for (const auto& add_element : to_add) {
1043
2.60k
        add_element.reduction_check();
1044
2.60k
        add_values += add_element.get_value();
1045
2.60k
        add_constant = add_constant && (add_element.is_constant());
1046
2.60k
    }
1047
1048
1.30k
    const uint1024_t left(get_value());
1049
1.30k
    const uint1024_t right(get_value());
1050
1.30k
    const uint1024_t add_right(add_values);
1051
1.30k
    const uint1024_t modulus(target_basis.modulus);
1052
1053
1.30k
    bigfield remainder;
1054
1.30k
    bigfield quotient;
1055
1.30k
    if (is_constant()) {
1056
0
        if (add_constant) {
1057
1058
0
            const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1059
0
            remainder = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1060
            // Merge tags
1061
0
            OriginTag new_tag = get_origin_tag();
1062
0
            for (auto& element : to_add) {
1063
0
                new_tag = OriginTag(new_tag, element.get_origin_tag());
1064
0
            }
1065
0
            remainder.set_origin_tag(new_tag);
1066
0
            return remainder;
1067
0
        } else {
1068
1069
0
            const auto [quotient_1024, remainder_1024] = (left * right).divmod(modulus);
1070
0
            std::vector<bigfield> new_to_add;
1071
0
            for (auto& add_element : to_add) {
1072
0
                new_to_add.push_back(add_element);
1073
0
            }
1074
1075
0
            new_to_add.push_back(bigfield(ctx, remainder_1024.lo.lo));
1076
0
            return sum(new_to_add);
1077
0
        }
1078
1.30k
    } else {
1079
1080
        // Check the quotient fits the range proof
1081
1.30k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1082
1.30k
            { get_maximum_value() }, { get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1083
1084
1.30k
        if (reduction_required) {
1085
0
            self_reduce();
1086
0
            return sqradd(to_add);
1087
0
        }
1088
1.30k
        const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
1089
1.30k
        uint512_t quotient_value = quotient_1024.lo;
1090
1.30k
        uint256_t remainder_value = remainder_1024.lo.lo;
1091
1092
1.30k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1093
1.30k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1094
1.30k
    };
1095
1.30k
    OriginTag new_tag = get_origin_tag();
1096
2.60k
    for (auto& element : to_add) {
1097
2.60k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1098
2.60k
    }
1099
1.30k
    remainder.set_origin_tag(new_tag);
1100
1.30k
    unsafe_evaluate_square_add(*this, to_add, quotient, remainder);
1101
1.30k
    return remainder;
1102
1.30k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE6sqraddERKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE6sqraddERKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE6sqraddERKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE6sqraddERKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE6sqraddERKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE6sqraddERKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E6sqraddERKSt6vectorIS7_SaIS7_EE
1103
1104
/**
1105
 * @brief Raise a bigfield to a power of an exponent. Note that the exponent must not exceed 32 bits and is
1106
 * implicitly range constrained.
1107
 *
1108
 * @returns this ** (exponent)
1109
 *
1110
 * @todo TODO(https://github.com/AztecProtocol/barretenberg/issues/1014) Improve the efficiency of this function.
1111
 */
1112
1113
template <typename Builder, typename T> bigfield<Builder, T> bigfield<Builder, T>::pow(const size_t exponent) const
1114
56
{
1115
    // Just return one immediately
1116
1117
56
    if (exponent == 0) {
1118
0
        return bigfield(uint256_t(1));
1119
0
    }
1120
1121
56
    bool accumulator_initialized = false;
1122
56
    bigfield accumulator;
1123
56
    bigfield running_power = *this;
1124
56
    auto shifted_exponent = exponent;
1125
1126
    // Square and multiply
1127
662
    while (shifted_exponent != 0) {
1128
606
        if (shifted_exponent & 1) {
1129
378
            if (!accumulator_initialized) {
1130
56
                accumulator = running_power;
1131
56
                accumulator_initialized = true;
1132
322
            } else {
1133
322
                accumulator *= running_power;
1134
322
            }
1135
378
        }
1136
606
        if (shifted_exponent != 0) {
1137
606
            running_power = running_power.sqr();
1138
606
        }
1139
606
        shifted_exponent >>= 1;
1140
606
    }
1141
56
    return accumulator;
1142
56
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3powEm
Line
Count
Source
1114
56
{
1115
    // Just return one immediately
1116
1117
56
    if (exponent == 0) {
1118
0
        return bigfield(uint256_t(1));
1119
0
    }
1120
1121
56
    bool accumulator_initialized = false;
1122
56
    bigfield accumulator;
1123
56
    bigfield running_power = *this;
1124
56
    auto shifted_exponent = exponent;
1125
1126
    // Square and multiply
1127
662
    while (shifted_exponent != 0) {
1128
606
        if (shifted_exponent & 1) {
1129
378
            if (!accumulator_initialized) {
1130
56
                accumulator = running_power;
1131
56
                accumulator_initialized = true;
1132
322
            } else {
1133
322
                accumulator *= running_power;
1134
322
            }
1135
378
        }
1136
606
        if (shifted_exponent != 0) {
1137
606
            running_power = running_power.sqr();
1138
606
        }
1139
606
        shifted_exponent >>= 1;
1140
606
    }
1141
56
    return accumulator;
1142
56
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE3powEm
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE3powEm
1143
1144
/**
1145
 * @brief Raise a bigfield to a power of an exponent (field_t) that must be a witness. Note that the exponent must
1146
 * not exceed 32 bits and is implicitly range constrained.
1147
 *
1148
 * @returns this ** (exponent)
1149
 *
1150
 * @todo TODO(https://github.com/AztecProtocol/barretenberg/issues/1014) Improve the efficiency of this function.
1151
 */
1152
template <typename Builder, typename T>
1153
bigfield<Builder, T> bigfield<Builder, T>::pow(const field_t<Builder>& exponent) const
1154
20
{
1155
20
    auto* ctx = get_context() ? get_context() : exponent.get_context();
1156
20
    uint256_t exponent_value = exponent.get_value();
1157
1158
20
    ASSERT(exponent_value.get_msb() < 32);
1159
    // Use the constant version that perfoms only the necessary multiplications if the exponent is constant
1160
20
    if (exponent.is_constant()) {
1161
0
        return this->pow(static_cast<uint32_t>(exponent_value));
1162
0
    }
1163
20
    std::vector<bool_t<Builder>> exponent_bits(32);
1164
    // Collect individual bits as bool_t's
1165
660
    for (size_t i = 0; i < exponent_bits.size(); ++i) {
1166
640
        uint256_t value_bit = exponent_value & 1;
1167
640
        bool_t<Builder> bit;
1168
640
        bit = bool_t<Builder>(witness_t<Builder>(ctx, value_bit.data[0]));
1169
640
        exponent_bits[31 - i] = (bit);
1170
640
        exponent_value >>= 1;
1171
640
    }
1172
1173
20
    field_t<Builder> exponent_accumulator(ctx, 0);
1174
1175
    // Reconstruct the exponent from bits
1176
640
    for (const auto& bit : exponent_bits) {
1177
640
        exponent_accumulator += exponent_accumulator;
1178
640
        exponent_accumulator += field_t<Builder>(bit);
1179
640
    }
1180
1181
    // Ensure it's equal to the original
1182
20
    exponent.assert_equal(exponent_accumulator, "field_t::pow exponent accumulator incorrect");
1183
20
    bigfield accumulator(ctx, 1);
1184
20
    bigfield one(1);
1185
    // Compute the power with a square-and-multiply algorithm
1186
660
    for (size_t digit_idx = 0; digit_idx < 32; ++digit_idx) {
1187
640
        accumulator *= accumulator;
1188
640
        accumulator *= one.conditional_select(*this, exponent_bits[digit_idx]);
1189
640
    }
1190
20
    accumulator.self_reduce();
1191
20
    accumulator.set_origin_tag(OriginTag(get_origin_tag(), exponent.tag));
1192
20
    return accumulator;
1193
0
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3powERKNS0_7field_tIS4_EE
Line
Count
Source
1154
20
{
1155
20
    auto* ctx = get_context() ? get_context() : exponent.get_context();
1156
20
    uint256_t exponent_value = exponent.get_value();
1157
1158
20
    ASSERT(exponent_value.get_msb() < 32);
1159
    // Use the constant version that perfoms only the necessary multiplications if the exponent is constant
1160
20
    if (exponent.is_constant()) {
1161
0
        return this->pow(static_cast<uint32_t>(exponent_value));
1162
0
    }
1163
20
    std::vector<bool_t<Builder>> exponent_bits(32);
1164
    // Collect individual bits as bool_t's
1165
660
    for (size_t i = 0; i < exponent_bits.size(); ++i) {
1166
640
        uint256_t value_bit = exponent_value & 1;
1167
640
        bool_t<Builder> bit;
1168
640
        bit = bool_t<Builder>(witness_t<Builder>(ctx, value_bit.data[0]));
1169
640
        exponent_bits[31 - i] = (bit);
1170
640
        exponent_value >>= 1;
1171
640
    }
1172
1173
20
    field_t<Builder> exponent_accumulator(ctx, 0);
1174
1175
    // Reconstruct the exponent from bits
1176
640
    for (const auto& bit : exponent_bits) {
1177
640
        exponent_accumulator += exponent_accumulator;
1178
640
        exponent_accumulator += field_t<Builder>(bit);
1179
640
    }
1180
1181
    // Ensure it's equal to the original
1182
20
    exponent.assert_equal(exponent_accumulator, "field_t::pow exponent accumulator incorrect");
1183
20
    bigfield accumulator(ctx, 1);
1184
20
    bigfield one(1);
1185
    // Compute the power with a square-and-multiply algorithm
1186
660
    for (size_t digit_idx = 0; digit_idx < 32; ++digit_idx) {
1187
640
        accumulator *= accumulator;
1188
640
        accumulator *= one.conditional_select(*this, exponent_bits[digit_idx]);
1189
640
    }
1190
20
    accumulator.self_reduce();
1191
20
    accumulator.set_origin_tag(OriginTag(get_origin_tag(), exponent.tag));
1192
20
    return accumulator;
1193
20
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3powERKNS0_7field_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3powERKNS0_7field_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3powERKNS0_7field_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE3powERKNS0_7field_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE3powERKNS0_7field_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE3powERKNS0_7field_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE3powERKNS0_7field_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE3powERKNS0_7field_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE3powERKNS0_7field_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE3powERKNS0_7field_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE3powERKNS0_7field_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE3powERKNS0_7field_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE3powERKNS0_7field_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE3powERKNS0_7field_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E3powERKNS0_7field_tIS6_EE
1194
1195
/**
1196
 * Compute a * b + ...to_add = c mod p
1197
 *
1198
 * @param to_mul Bigfield element to multiply by
1199
 * @param to_add Vector of elements to add
1200
 *
1201
 * @return New bigfield elment c
1202
 **/
1203
template <typename Builder, typename T>
1204
bigfield<Builder, T> bigfield<Builder, T>::madd(const bigfield& to_mul, const std::vector<bigfield>& to_add) const
1205
121k
{
1206
121k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1207
121k
    Builder* ctx = context ? context : to_mul.context;
1208
0
    reduction_check();
1209
0
    to_mul.reduction_check();
1210
1211
0
    uint512_t add_values(0);
1212
0
    bool add_constant = true;
1213
1214
197k
    for (const auto& add_element : to_add) {
1215
197k
        add_element.reduction_check();
1216
197k
        add_values += add_element.get_value();
1217
197k
        add_constant = add_constant && (add_element.is_constant());
1218
197k
    }
1219
1220
0
    const uint1024_t left(get_value());
1221
0
    const uint1024_t mul_right(to_mul.get_value());
1222
0
    const uint1024_t add_right(add_values);
1223
0
    const uint1024_t modulus(target_basis.modulus);
1224
1225
0
    const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus);
1226
1227
0
    const uint512_t quotient_value = quotient_1024.lo;
1228
0
    const uint512_t remainder_value = remainder_1024.lo;
1229
1230
0
    bigfield remainder;
1231
0
    bigfield quotient;
1232
121k
    if (is_constant() && to_mul.is_constant() && add_constant) {
1233
2
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1234
2
        return remainder;
1235
121k
    } else {
1236
1237
121k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1238
121k
            { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1239
121k
        if (reduction_required) {
1240
1
            if (get_maximum_value() > to_mul.get_maximum_value()) {
1241
0
                self_reduce();
1242
1
            } else {
1243
1
                to_mul.self_reduce();
1244
1
            }
1245
1
            return (*this).madd(to_mul, to_add);
1246
1
        }
1247
121k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1248
121k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1249
121k
    };
1250
121k
    unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder });
1251
121k
    OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag());
1252
197k
    for (auto& element : to_add) {
1253
197k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1254
197k
    }
1255
121k
    return remainder;
1256
0
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE4maddERKS6_RKSt6vectorIS6_SaIS6_EE
Line
Count
Source
1205
98.8k
{
1206
98.8k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1207
98.8k
    Builder* ctx = context ? context : to_mul.context;
1208
98.8k
    reduction_check();
1209
98.8k
    to_mul.reduction_check();
1210
1211
98.8k
    uint512_t add_values(0);
1212
98.8k
    bool add_constant = true;
1213
1214
158k
    for (const auto& add_element : to_add) {
1215
158k
        add_element.reduction_check();
1216
158k
        add_values += add_element.get_value();
1217
158k
        add_constant = add_constant && (add_element.is_constant());
1218
158k
    }
1219
1220
98.8k
    const uint1024_t left(get_value());
1221
98.8k
    const uint1024_t mul_right(to_mul.get_value());
1222
98.8k
    const uint1024_t add_right(add_values);
1223
98.8k
    const uint1024_t modulus(target_basis.modulus);
1224
1225
98.8k
    const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus);
1226
1227
98.8k
    const uint512_t quotient_value = quotient_1024.lo;
1228
98.8k
    const uint512_t remainder_value = remainder_1024.lo;
1229
1230
98.8k
    bigfield remainder;
1231
98.8k
    bigfield quotient;
1232
98.8k
    if (is_constant() && to_mul.is_constant() && add_constant) {
1233
2
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1234
2
        return remainder;
1235
98.8k
    } else {
1236
1237
98.8k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1238
98.8k
            { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1239
98.8k
        if (reduction_required) {
1240
1
            if (get_maximum_value() > to_mul.get_maximum_value()) {
1241
0
                self_reduce();
1242
1
            } else {
1243
1
                to_mul.self_reduce();
1244
1
            }
1245
1
            return (*this).madd(to_mul, to_add);
1246
1
        }
1247
98.8k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1248
98.8k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1249
98.8k
    };
1250
98.8k
    unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder });
1251
98.8k
    OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag());
1252
158k
    for (auto& element : to_add) {
1253
158k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1254
158k
    }
1255
98.8k
    return remainder;
1256
98.8k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE4maddERKS6_RKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE4maddERKS8_RKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E4maddERKS7_RKSt6vectorIS7_SaIS7_EE
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE4maddERKS7_RKSt6vectorIS7_SaIS7_EE
Line
Count
Source
1205
974
{
1206
974
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1207
974
    Builder* ctx = context ? context : to_mul.context;
1208
974
    reduction_check();
1209
974
    to_mul.reduction_check();
1210
1211
974
    uint512_t add_values(0);
1212
974
    bool add_constant = true;
1213
1214
1.55k
    for (const auto& add_element : to_add) {
1215
1.55k
        add_element.reduction_check();
1216
1.55k
        add_values += add_element.get_value();
1217
1.55k
        add_constant = add_constant && (add_element.is_constant());
1218
1.55k
    }
1219
1220
974
    const uint1024_t left(get_value());
1221
974
    const uint1024_t mul_right(to_mul.get_value());
1222
974
    const uint1024_t add_right(add_values);
1223
974
    const uint1024_t modulus(target_basis.modulus);
1224
1225
974
    const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus);
1226
1227
974
    const uint512_t quotient_value = quotient_1024.lo;
1228
974
    const uint512_t remainder_value = remainder_1024.lo;
1229
1230
974
    bigfield remainder;
1231
974
    bigfield quotient;
1232
974
    if (is_constant() && to_mul.is_constant() && add_constant) {
1233
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1234
0
        return remainder;
1235
974
    } else {
1236
1237
974
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1238
974
            { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1239
974
        if (reduction_required) {
1240
0
            if (get_maximum_value() > to_mul.get_maximum_value()) {
1241
0
                self_reduce();
1242
0
            } else {
1243
0
                to_mul.self_reduce();
1244
0
            }
1245
0
            return (*this).madd(to_mul, to_add);
1246
0
        }
1247
974
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1248
974
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1249
974
    };
1250
974
    unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder });
1251
974
    OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag());
1252
1.55k
    for (auto& element : to_add) {
1253
1.55k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1254
1.55k
    }
1255
974
    return remainder;
1256
974
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE4maddERKS7_RKSt6vectorIS7_SaIS7_EE
Line
Count
Source
1205
12
{
1206
12
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1207
12
    Builder* ctx = context ? context : to_mul.context;
1208
12
    reduction_check();
1209
12
    to_mul.reduction_check();
1210
1211
12
    uint512_t add_values(0);
1212
12
    bool add_constant = true;
1213
1214
12
    for (const auto& add_element : to_add) {
1215
12
        add_element.reduction_check();
1216
12
        add_values += add_element.get_value();
1217
12
        add_constant = add_constant && (add_element.is_constant());
1218
12
    }
1219
1220
12
    const uint1024_t left(get_value());
1221
12
    const uint1024_t mul_right(to_mul.get_value());
1222
12
    const uint1024_t add_right(add_values);
1223
12
    const uint1024_t modulus(target_basis.modulus);
1224
1225
12
    const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus);
1226
1227
12
    const uint512_t quotient_value = quotient_1024.lo;
1228
12
    const uint512_t remainder_value = remainder_1024.lo;
1229
1230
12
    bigfield remainder;
1231
12
    bigfield quotient;
1232
12
    if (is_constant() && to_mul.is_constant() && add_constant) {
1233
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1234
0
        return remainder;
1235
12
    } else {
1236
1237
12
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1238
12
            { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1239
12
        if (reduction_required) {
1240
0
            if (get_maximum_value() > to_mul.get_maximum_value()) {
1241
0
                self_reduce();
1242
0
            } else {
1243
0
                to_mul.self_reduce();
1244
0
            }
1245
0
            return (*this).madd(to_mul, to_add);
1246
0
        }
1247
12
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1248
12
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1249
12
    };
1250
12
    unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder });
1251
12
    OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag());
1252
12
    for (auto& element : to_add) {
1253
12
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1254
12
    }
1255
12
    return remainder;
1256
12
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE4maddERKS9_RKSt6vectorIS9_SaIS9_EE
Line
Count
Source
1205
20.3k
{
1206
20.3k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1207
20.3k
    Builder* ctx = context ? context : to_mul.context;
1208
20.3k
    reduction_check();
1209
20.3k
    to_mul.reduction_check();
1210
1211
20.3k
    uint512_t add_values(0);
1212
20.3k
    bool add_constant = true;
1213
1214
34.1k
    for (const auto& add_element : to_add) {
1215
34.1k
        add_element.reduction_check();
1216
34.1k
        add_values += add_element.get_value();
1217
34.1k
        add_constant = add_constant && (add_element.is_constant());
1218
34.1k
    }
1219
1220
20.3k
    const uint1024_t left(get_value());
1221
20.3k
    const uint1024_t mul_right(to_mul.get_value());
1222
20.3k
    const uint1024_t add_right(add_values);
1223
20.3k
    const uint1024_t modulus(target_basis.modulus);
1224
1225
20.3k
    const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus);
1226
1227
20.3k
    const uint512_t quotient_value = quotient_1024.lo;
1228
20.3k
    const uint512_t remainder_value = remainder_1024.lo;
1229
1230
20.3k
    bigfield remainder;
1231
20.3k
    bigfield quotient;
1232
20.3k
    if (is_constant() && to_mul.is_constant() && add_constant) {
1233
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1234
0
        return remainder;
1235
20.3k
    } else {
1236
1237
20.3k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1238
20.3k
            { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1239
20.3k
        if (reduction_required) {
1240
0
            if (get_maximum_value() > to_mul.get_maximum_value()) {
1241
0
                self_reduce();
1242
0
            } else {
1243
0
                to_mul.self_reduce();
1244
0
            }
1245
0
            return (*this).madd(to_mul, to_add);
1246
0
        }
1247
20.3k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1248
20.3k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1249
20.3k
    };
1250
20.3k
    unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder });
1251
20.3k
    OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag());
1252
34.1k
    for (auto& element : to_add) {
1253
34.1k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1254
34.1k
    }
1255
20.3k
    return remainder;
1256
20.3k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE4maddERKS9_RKSt6vectorIS9_SaIS9_EE
Line
Count
Source
1205
288
{
1206
288
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1207
288
    Builder* ctx = context ? context : to_mul.context;
1208
288
    reduction_check();
1209
288
    to_mul.reduction_check();
1210
1211
288
    uint512_t add_values(0);
1212
288
    bool add_constant = true;
1213
1214
288
    for (const auto& add_element : to_add) {
1215
288
        add_element.reduction_check();
1216
288
        add_values += add_element.get_value();
1217
288
        add_constant = add_constant && (add_element.is_constant());
1218
288
    }
1219
1220
288
    const uint1024_t left(get_value());
1221
288
    const uint1024_t mul_right(to_mul.get_value());
1222
288
    const uint1024_t add_right(add_values);
1223
288
    const uint1024_t modulus(target_basis.modulus);
1224
1225
288
    const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus);
1226
1227
288
    const uint512_t quotient_value = quotient_1024.lo;
1228
288
    const uint512_t remainder_value = remainder_1024.lo;
1229
1230
288
    bigfield remainder;
1231
288
    bigfield quotient;
1232
288
    if (is_constant() && to_mul.is_constant() && add_constant) {
1233
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1234
0
        return remainder;
1235
288
    } else {
1236
1237
288
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1238
288
            { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1239
288
        if (reduction_required) {
1240
0
            if (get_maximum_value() > to_mul.get_maximum_value()) {
1241
0
                self_reduce();
1242
0
            } else {
1243
0
                to_mul.self_reduce();
1244
0
            }
1245
0
            return (*this).madd(to_mul, to_add);
1246
0
        }
1247
288
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1248
288
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1249
288
    };
1250
288
    unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder });
1251
288
    OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag());
1252
288
    for (auto& element : to_add) {
1253
288
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1254
288
    }
1255
288
    return remainder;
1256
288
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE4maddERKS7_RKSt6vectorIS7_SaIS7_EE
Line
Count
Source
1205
1.30k
{
1206
1.30k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1207
1.30k
    Builder* ctx = context ? context : to_mul.context;
1208
1.30k
    reduction_check();
1209
1.30k
    to_mul.reduction_check();
1210
1211
1.30k
    uint512_t add_values(0);
1212
1.30k
    bool add_constant = true;
1213
1214
2.58k
    for (const auto& add_element : to_add) {
1215
2.58k
        add_element.reduction_check();
1216
2.58k
        add_values += add_element.get_value();
1217
2.58k
        add_constant = add_constant && (add_element.is_constant());
1218
2.58k
    }
1219
1220
1.30k
    const uint1024_t left(get_value());
1221
1.30k
    const uint1024_t mul_right(to_mul.get_value());
1222
1.30k
    const uint1024_t add_right(add_values);
1223
1.30k
    const uint1024_t modulus(target_basis.modulus);
1224
1225
1.30k
    const auto [quotient_1024, remainder_1024] = (left * mul_right + add_right).divmod(modulus);
1226
1227
1.30k
    const uint512_t quotient_value = quotient_1024.lo;
1228
1.30k
    const uint512_t remainder_value = remainder_1024.lo;
1229
1230
1.30k
    bigfield remainder;
1231
1.30k
    bigfield quotient;
1232
1.30k
    if (is_constant() && to_mul.is_constant() && add_constant) {
1233
0
        remainder = bigfield(ctx, uint256_t(remainder_value.lo));
1234
0
        return remainder;
1235
1.30k
    } else {
1236
1237
1.30k
        auto [reduction_required, num_quotient_bits] = get_quotient_reduction_info(
1238
1.30k
            { get_maximum_value() }, { to_mul.get_maximum_value() }, to_add, { DEFAULT_MAXIMUM_REMAINDER });
1239
1.30k
        if (reduction_required) {
1240
0
            if (get_maximum_value() > to_mul.get_maximum_value()) {
1241
0
                self_reduce();
1242
0
            } else {
1243
0
                to_mul.self_reduce();
1244
0
            }
1245
0
            return (*this).madd(to_mul, to_add);
1246
0
        }
1247
1.30k
        quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1248
1.30k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1249
1.30k
    };
1250
1.30k
    unsafe_evaluate_multiply_add(*this, to_mul, to_add, quotient, { remainder });
1251
1.30k
    OriginTag new_tag = OriginTag(get_origin_tag(), to_mul.get_origin_tag());
1252
2.58k
    for (auto& element : to_add) {
1253
2.58k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1254
2.58k
    }
1255
1.30k
    return remainder;
1256
1.30k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE4maddERKS7_RKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE4maddERKS9_RKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE4maddERKS9_RKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE4maddERKS6_RKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE4maddERKS6_RKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE4maddERKS8_RKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E4maddERKS7_RKSt6vectorIS7_SaIS7_EE
1257
1258
// MERGENOTE: Implementing dual_madd in terms of mult_madd following #729
1259
1260
/**
1261
 * @brief Performs individual reductions on the supplied elements as well as more complex reductions to prevent CRT
1262
 * modulus overflow and to fit the quotient inside the range proof
1263
 *
1264
 *
1265
 * @tparam Builder builder
1266
 * @tparam T basefield
1267
 * @param mul_left
1268
 * @param mul_right
1269
 * @param to_add
1270
 */
1271
template <typename Builder, typename T>
1272
void bigfield<Builder, T>::perform_reductions_for_mult_madd(std::vector<bigfield>& mul_left,
1273
                                                            std::vector<bigfield>& mul_right,
1274
                                                            const std::vector<bigfield>& to_add)
1275
370k
{
1276
370k
    ASSERT(mul_left.size() == mul_right.size());
1277
370k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1278
370k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1279
1280
0
    const size_t number_of_products = mul_left.size();
1281
    // Get the maximum values of elements
1282
0
    std::vector<uint512_t> max_values_left;
1283
0
    std::vector<uint512_t> max_values_right;
1284
1285
0
    max_values_left.reserve(number_of_products);
1286
0
    max_values_right.reserve(number_of_products);
1287
    // Do regular reduction checks for all elements
1288
824k
    for (auto& left_element : mul_left) {
1289
824k
        left_element.reduction_check();
1290
824k
        max_values_left.emplace_back(left_element.get_maximum_value());
1291
824k
    }
1292
1293
824k
    for (auto& right_element : mul_right) {
1294
824k
        right_element.reduction_check();
1295
824k
        max_values_right.emplace_back(right_element.get_maximum_value());
1296
824k
    }
1297
1298
    // Perform CRT checks for the whole evaluation
1299
    // 1. Check if we can overflow CRT modulus
1300
    // 2. Check if the quotient actually fits in our range proof.
1301
    // 3. If we haven't passed one of the checks, reduce accordingly, starting with the largest product
1302
1303
    // We only get the bitlength of range proof if there is no reduction
1304
0
    bool reduction_required;
1305
0
    reduction_required = std::get<0>(
1306
0
        get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1307
1308
370k
    if (reduction_required) {
1309
1310
        // We are out of luck and have to reduce the elements to keep the intermediate result below CRT modulus
1311
        // For that we need to compute the maximum update - how much reducing each element is going to update the
1312
        // quotient.
1313
        // Contents of the tuple: | Qmax_before-Qmax_after | product number | argument number |
1314
1
        std::vector<std::tuple<uint1024_t, size_t, size_t>> maximum_value_updates;
1315
1316
        // We use this lambda function before the loop and in the loop itself
1317
        // It computes the maximum value update from reduction of each element
1318
1
        auto compute_updates = [](std::vector<std::tuple<uint1024_t, size_t, size_t>>& maxval_updates,
1319
1
                                  std::vector<bigfield>& m_left,
1320
1
                                  std::vector<bigfield>& m_right,
1321
1
                                  size_t number_of_products) {
1322
1
            maxval_updates.resize(0);
1323
1
            maxval_updates.reserve(number_of_products * 2);
1324
            // Compute all reduction differences
1325
2
            for (size_t i = 0; i < number_of_products; i++) {
1326
1
                uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value());
1327
1
                uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value());
1328
1
                uint1024_t original_product = original_left * original_right;
1329
1
                if (m_left[i].is_constant()) {
1330
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1331
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0));
1332
1
                } else {
1333
1
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right;
1334
1
                    if (new_product > original_product) {
1335
0
                        throw_or_abort("bigfield: This should never happen");
1336
0
                    }
1337
1
                    maxval_updates.emplace_back(
1338
1
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0));
1339
1
                }
1340
1
                if (m_right[i].is_constant()) {
1341
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1342
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1));
1343
1
                } else {
1344
1
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left;
1345
1
                    if (new_product > original_product) {
1346
0
                        throw_or_abort("bigfield: This should never happen");
1347
0
                    }
1348
1
                    maxval_updates.emplace_back(
1349
1
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1));
1350
1
                }
1351
1
            }
1352
1
        };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_ENKUlRS7_ISt5tupleIJNS_7numeric5uintxINSF_INSE_9uint256_tEEEEEmmEESaISJ_EESA_SA_mE_clESM_SA_SA_m
Line
Count
Source
1321
1
                                  size_t number_of_products) {
1322
1
            maxval_updates.resize(0);
1323
1
            maxval_updates.reserve(number_of_products * 2);
1324
            // Compute all reduction differences
1325
2
            for (size_t i = 0; i < number_of_products; i++) {
1326
1
                uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value());
1327
1
                uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value());
1328
1
                uint1024_t original_product = original_left * original_right;
1329
1
                if (m_left[i].is_constant()) {
1330
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1331
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0));
1332
1
                } else {
1333
1
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right;
1334
1
                    if (new_product > original_product) {
1335
0
                        throw_or_abort("bigfield: This should never happen");
1336
0
                    }
1337
1
                    maxval_updates.emplace_back(
1338
1
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0));
1339
1
                }
1340
1
                if (m_right[i].is_constant()) {
1341
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1342
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1));
1343
1
                } else {
1344
1
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left;
1345
1
                    if (new_product > original_product) {
1346
0
                        throw_or_abort("bigfield: This should never happen");
1347
0
                    }
1348
1
                    maxval_updates.emplace_back(
1349
1
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1));
1350
1
                }
1351
1
            }
1352
1
        };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_ENKUlRS7_ISt5tupleIJNS_7numeric5uintxINSF_INSE_9uint256_tEEEEEmmEESaISJ_EESA_SA_mE_clESM_SA_SA_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS8_SaIS8_EESC_RKSB_ENKUlRS9_ISt5tupleIJNS_7numeric5uintxINSH_INSG_9uint256_tEEEEEmmEESaISL_EESC_SC_mE_clESO_SC_SC_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRS8_ISt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESaISK_EESB_SB_mE_clESN_SB_SB_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRS8_ISt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESaISK_EESB_SB_mE_clESN_SB_SB_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRS8_ISt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESaISK_EESB_SB_mE_clESN_SB_SB_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSA_ISt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESaISM_EESD_SD_mE_clESP_SD_SD_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSA_ISt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESaISM_EESD_SD_mE_clESP_SD_SD_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRS8_ISt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESaISK_EESB_SB_mE_clESN_SB_SB_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRS8_ISt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESaISK_EESB_SB_mE_clESN_SB_SB_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSA_ISt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESaISM_EESD_SD_mE_clESP_SD_SD_m
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSA_ISt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESaISM_EESD_SD_mE_clESP_SD_SD_m
1353
1354
1
        auto compare_update_tuples = [](std::tuple<uint1024_t, size_t, size_t>& left_element,
1355
2
                                        std::tuple<uint1024_t, size_t, size_t>& right_element) {
1356
2
            return std::get<0>(left_element) > std::get<0>(right_element);
1357
2
        };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_ENKUlRSt5tupleIJNS_7numeric5uintxINSF_INSE_9uint256_tEEEEEmmEESK_E_clESK_SK_
Line
Count
Source
1355
2
                                        std::tuple<uint1024_t, size_t, size_t>& right_element) {
1356
2
            return std::get<0>(left_element) > std::get<0>(right_element);
1357
2
        };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_ENKUlRSt5tupleIJNS_7numeric5uintxINSF_INSE_9uint256_tEEEEEmmEESK_E_clESK_SK_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS8_SaIS8_EESC_RKSB_ENKUlRSt5tupleIJNS_7numeric5uintxINSH_INSG_9uint256_tEEEEEmmEESM_E_clESM_SM_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRSt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESL_E_clESL_SL_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRSt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESL_E_clESL_SL_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRSt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESL_E_clESL_SL_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESN_E_clESN_SN_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESN_E_clESN_SN_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRSt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESL_E_clESL_SL_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_ENKUlRSt5tupleIJNS_7numeric5uintxINSG_INSF_9uint256_tEEEEEmmEESL_E_clESL_SL_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESN_E_clESN_SN_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_ENKUlRSt5tupleIJNS_7numeric5uintxINSI_INSH_9uint256_tEEEEEmmEESN_E_clESN_SN_
1358
1359
        // Now we loop through, reducing 1 element each time. This is costly in code, but allows us to use fewer
1360
        // gates
1361
1362
2
        while (reduction_required) {
1363
            // Compute the possible reduction updates
1364
1
            compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products);
1365
1366
            // Sort the vector, larger values first
1367
1
            std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples);
1368
1369
            // We choose the largest update
1370
1
            auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0];
1371
1
            if (!update_size) {
1372
0
                throw_or_abort("bigfield: Can't reduce further");
1373
0
            }
1374
            // Reduce the larger of the multiplicands that compose the product
1375
1
            if (multiplicand_index == 0) {
1376
1
                mul_left[largest_update_product_index].self_reduce();
1377
1
            } else {
1378
0
                mul_right[largest_update_product_index].self_reduce();
1379
0
            }
1380
1381
2
            for (size_t i = 0; i < number_of_products; i++) {
1382
1
                max_values_left[i] = mul_left[i].get_maximum_value();
1383
1
                max_values_right[i] = mul_right[i].get_maximum_value();
1384
1
            }
1385
1
            reduction_required = std::get<0>(
1386
1
                get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1387
1
        }
1388
1389
        // Now we have reduced everything exactly to the point of no overflow. There is probably a way to use even
1390
        // fewer reductions, but for now this will suffice.
1391
1
    }
1392
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_
Line
Count
Source
1275
338k
{
1276
338k
    ASSERT(mul_left.size() == mul_right.size());
1277
338k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1278
338k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1279
1280
338k
    const size_t number_of_products = mul_left.size();
1281
    // Get the maximum values of elements
1282
338k
    std::vector<uint512_t> max_values_left;
1283
338k
    std::vector<uint512_t> max_values_right;
1284
1285
338k
    max_values_left.reserve(number_of_products);
1286
338k
    max_values_right.reserve(number_of_products);
1287
    // Do regular reduction checks for all elements
1288
743k
    for (auto& left_element : mul_left) {
1289
743k
        left_element.reduction_check();
1290
743k
        max_values_left.emplace_back(left_element.get_maximum_value());
1291
743k
    }
1292
1293
743k
    for (auto& right_element : mul_right) {
1294
743k
        right_element.reduction_check();
1295
743k
        max_values_right.emplace_back(right_element.get_maximum_value());
1296
743k
    }
1297
1298
    // Perform CRT checks for the whole evaluation
1299
    // 1. Check if we can overflow CRT modulus
1300
    // 2. Check if the quotient actually fits in our range proof.
1301
    // 3. If we haven't passed one of the checks, reduce accordingly, starting with the largest product
1302
1303
    // We only get the bitlength of range proof if there is no reduction
1304
338k
    bool reduction_required;
1305
338k
    reduction_required = std::get<0>(
1306
338k
        get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1307
1308
338k
    if (reduction_required) {
1309
1310
        // We are out of luck and have to reduce the elements to keep the intermediate result below CRT modulus
1311
        // For that we need to compute the maximum update - how much reducing each element is going to update the
1312
        // quotient.
1313
        // Contents of the tuple: | Qmax_before-Qmax_after | product number | argument number |
1314
1
        std::vector<std::tuple<uint1024_t, size_t, size_t>> maximum_value_updates;
1315
1316
        // We use this lambda function before the loop and in the loop itself
1317
        // It computes the maximum value update from reduction of each element
1318
1
        auto compute_updates = [](std::vector<std::tuple<uint1024_t, size_t, size_t>>& maxval_updates,
1319
1
                                  std::vector<bigfield>& m_left,
1320
1
                                  std::vector<bigfield>& m_right,
1321
1
                                  size_t number_of_products) {
1322
1
            maxval_updates.resize(0);
1323
1
            maxval_updates.reserve(number_of_products * 2);
1324
            // Compute all reduction differences
1325
1
            for (size_t i = 0; i < number_of_products; i++) {
1326
1
                uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value());
1327
1
                uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value());
1328
1
                uint1024_t original_product = original_left * original_right;
1329
1
                if (m_left[i].is_constant()) {
1330
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1331
1
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0));
1332
1
                } else {
1333
1
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right;
1334
1
                    if (new_product > original_product) {
1335
1
                        throw_or_abort("bigfield: This should never happen");
1336
1
                    }
1337
1
                    maxval_updates.emplace_back(
1338
1
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0));
1339
1
                }
1340
1
                if (m_right[i].is_constant()) {
1341
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1342
1
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1));
1343
1
                } else {
1344
1
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left;
1345
1
                    if (new_product > original_product) {
1346
1
                        throw_or_abort("bigfield: This should never happen");
1347
1
                    }
1348
1
                    maxval_updates.emplace_back(
1349
1
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1));
1350
1
                }
1351
1
            }
1352
1
        };
1353
1354
1
        auto compare_update_tuples = [](std::tuple<uint1024_t, size_t, size_t>& left_element,
1355
1
                                        std::tuple<uint1024_t, size_t, size_t>& right_element) {
1356
1
            return std::get<0>(left_element) > std::get<0>(right_element);
1357
1
        };
1358
1359
        // Now we loop through, reducing 1 element each time. This is costly in code, but allows us to use fewer
1360
        // gates
1361
1362
2
        while (reduction_required) {
1363
            // Compute the possible reduction updates
1364
1
            compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products);
1365
1366
            // Sort the vector, larger values first
1367
1
            std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples);
1368
1369
            // We choose the largest update
1370
1
            auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0];
1371
1
            if (!update_size) {
1372
0
                throw_or_abort("bigfield: Can't reduce further");
1373
0
            }
1374
            // Reduce the larger of the multiplicands that compose the product
1375
1
            if (multiplicand_index == 0) {
1376
1
                mul_left[largest_update_product_index].self_reduce();
1377
1
            } else {
1378
0
                mul_right[largest_update_product_index].self_reduce();
1379
0
            }
1380
1381
2
            for (size_t i = 0; i < number_of_products; i++) {
1382
1
                max_values_left[i] = mul_left[i].get_maximum_value();
1383
1
                max_values_right[i] = mul_right[i].get_maximum_value();
1384
1
            }
1385
1
            reduction_required = std::get<0>(
1386
1
                get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1387
1
        }
1388
1389
        // Now we have reduced everything exactly to the point of no overflow. There is probably a way to use even
1390
        // fewer reductions, but for now this will suffice.
1391
1
    }
1392
338k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS8_SaIS8_EESC_RKSB_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_
Line
Count
Source
1275
1.29k
{
1276
1.29k
    ASSERT(mul_left.size() == mul_right.size());
1277
1.29k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1278
1.29k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1279
1280
1.29k
    const size_t number_of_products = mul_left.size();
1281
    // Get the maximum values of elements
1282
1.29k
    std::vector<uint512_t> max_values_left;
1283
1.29k
    std::vector<uint512_t> max_values_right;
1284
1285
1.29k
    max_values_left.reserve(number_of_products);
1286
1.29k
    max_values_right.reserve(number_of_products);
1287
    // Do regular reduction checks for all elements
1288
3.15k
    for (auto& left_element : mul_left) {
1289
3.15k
        left_element.reduction_check();
1290
3.15k
        max_values_left.emplace_back(left_element.get_maximum_value());
1291
3.15k
    }
1292
1293
3.15k
    for (auto& right_element : mul_right) {
1294
3.15k
        right_element.reduction_check();
1295
3.15k
        max_values_right.emplace_back(right_element.get_maximum_value());
1296
3.15k
    }
1297
1298
    // Perform CRT checks for the whole evaluation
1299
    // 1. Check if we can overflow CRT modulus
1300
    // 2. Check if the quotient actually fits in our range proof.
1301
    // 3. If we haven't passed one of the checks, reduce accordingly, starting with the largest product
1302
1303
    // We only get the bitlength of range proof if there is no reduction
1304
1.29k
    bool reduction_required;
1305
1.29k
    reduction_required = std::get<0>(
1306
1.29k
        get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1307
1308
1.29k
    if (reduction_required) {
1309
1310
        // We are out of luck and have to reduce the elements to keep the intermediate result below CRT modulus
1311
        // For that we need to compute the maximum update - how much reducing each element is going to update the
1312
        // quotient.
1313
        // Contents of the tuple: | Qmax_before-Qmax_after | product number | argument number |
1314
0
        std::vector<std::tuple<uint1024_t, size_t, size_t>> maximum_value_updates;
1315
1316
        // We use this lambda function before the loop and in the loop itself
1317
        // It computes the maximum value update from reduction of each element
1318
0
        auto compute_updates = [](std::vector<std::tuple<uint1024_t, size_t, size_t>>& maxval_updates,
1319
0
                                  std::vector<bigfield>& m_left,
1320
0
                                  std::vector<bigfield>& m_right,
1321
0
                                  size_t number_of_products) {
1322
0
            maxval_updates.resize(0);
1323
0
            maxval_updates.reserve(number_of_products * 2);
1324
            // Compute all reduction differences
1325
0
            for (size_t i = 0; i < number_of_products; i++) {
1326
0
                uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value());
1327
0
                uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value());
1328
0
                uint1024_t original_product = original_left * original_right;
1329
0
                if (m_left[i].is_constant()) {
1330
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1331
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0));
1332
0
                } else {
1333
0
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right;
1334
0
                    if (new_product > original_product) {
1335
0
                        throw_or_abort("bigfield: This should never happen");
1336
0
                    }
1337
0
                    maxval_updates.emplace_back(
1338
0
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0));
1339
0
                }
1340
0
                if (m_right[i].is_constant()) {
1341
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1342
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1));
1343
0
                } else {
1344
0
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left;
1345
0
                    if (new_product > original_product) {
1346
0
                        throw_or_abort("bigfield: This should never happen");
1347
0
                    }
1348
0
                    maxval_updates.emplace_back(
1349
0
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1));
1350
0
                }
1351
0
            }
1352
0
        };
1353
1354
0
        auto compare_update_tuples = [](std::tuple<uint1024_t, size_t, size_t>& left_element,
1355
0
                                        std::tuple<uint1024_t, size_t, size_t>& right_element) {
1356
0
            return std::get<0>(left_element) > std::get<0>(right_element);
1357
0
        };
1358
1359
        // Now we loop through, reducing 1 element each time. This is costly in code, but allows us to use fewer
1360
        // gates
1361
1362
0
        while (reduction_required) {
1363
            // Compute the possible reduction updates
1364
0
            compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products);
1365
1366
            // Sort the vector, larger values first
1367
0
            std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples);
1368
1369
            // We choose the largest update
1370
0
            auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0];
1371
0
            if (!update_size) {
1372
0
                throw_or_abort("bigfield: Can't reduce further");
1373
0
            }
1374
            // Reduce the larger of the multiplicands that compose the product
1375
0
            if (multiplicand_index == 0) {
1376
0
                mul_left[largest_update_product_index].self_reduce();
1377
0
            } else {
1378
0
                mul_right[largest_update_product_index].self_reduce();
1379
0
            }
1380
1381
0
            for (size_t i = 0; i < number_of_products; i++) {
1382
0
                max_values_left[i] = mul_left[i].get_maximum_value();
1383
0
                max_values_right[i] = mul_right[i].get_maximum_value();
1384
0
            }
1385
0
            reduction_required = std::get<0>(
1386
0
                get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1387
0
        }
1388
1389
        // Now we have reduced everything exactly to the point of no overflow. There is probably a way to use even
1390
        // fewer reductions, but for now this will suffice.
1391
0
    }
1392
1.29k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_
Line
Count
Source
1275
28.3k
{
1276
28.3k
    ASSERT(mul_left.size() == mul_right.size());
1277
28.3k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1278
28.3k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1279
1280
28.3k
    const size_t number_of_products = mul_left.size();
1281
    // Get the maximum values of elements
1282
28.3k
    std::vector<uint512_t> max_values_left;
1283
28.3k
    std::vector<uint512_t> max_values_right;
1284
1285
28.3k
    max_values_left.reserve(number_of_products);
1286
28.3k
    max_values_right.reserve(number_of_products);
1287
    // Do regular reduction checks for all elements
1288
70.5k
    for (auto& left_element : mul_left) {
1289
70.5k
        left_element.reduction_check();
1290
70.5k
        max_values_left.emplace_back(left_element.get_maximum_value());
1291
70.5k
    }
1292
1293
70.5k
    for (auto& right_element : mul_right) {
1294
70.5k
        right_element.reduction_check();
1295
70.5k
        max_values_right.emplace_back(right_element.get_maximum_value());
1296
70.5k
    }
1297
1298
    // Perform CRT checks for the whole evaluation
1299
    // 1. Check if we can overflow CRT modulus
1300
    // 2. Check if the quotient actually fits in our range proof.
1301
    // 3. If we haven't passed one of the checks, reduce accordingly, starting with the largest product
1302
1303
    // We only get the bitlength of range proof if there is no reduction
1304
28.3k
    bool reduction_required;
1305
28.3k
    reduction_required = std::get<0>(
1306
28.3k
        get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1307
1308
28.3k
    if (reduction_required) {
1309
1310
        // We are out of luck and have to reduce the elements to keep the intermediate result below CRT modulus
1311
        // For that we need to compute the maximum update - how much reducing each element is going to update the
1312
        // quotient.
1313
        // Contents of the tuple: | Qmax_before-Qmax_after | product number | argument number |
1314
0
        std::vector<std::tuple<uint1024_t, size_t, size_t>> maximum_value_updates;
1315
1316
        // We use this lambda function before the loop and in the loop itself
1317
        // It computes the maximum value update from reduction of each element
1318
0
        auto compute_updates = [](std::vector<std::tuple<uint1024_t, size_t, size_t>>& maxval_updates,
1319
0
                                  std::vector<bigfield>& m_left,
1320
0
                                  std::vector<bigfield>& m_right,
1321
0
                                  size_t number_of_products) {
1322
0
            maxval_updates.resize(0);
1323
0
            maxval_updates.reserve(number_of_products * 2);
1324
            // Compute all reduction differences
1325
0
            for (size_t i = 0; i < number_of_products; i++) {
1326
0
                uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value());
1327
0
                uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value());
1328
0
                uint1024_t original_product = original_left * original_right;
1329
0
                if (m_left[i].is_constant()) {
1330
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1331
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0));
1332
0
                } else {
1333
0
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right;
1334
0
                    if (new_product > original_product) {
1335
0
                        throw_or_abort("bigfield: This should never happen");
1336
0
                    }
1337
0
                    maxval_updates.emplace_back(
1338
0
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0));
1339
0
                }
1340
0
                if (m_right[i].is_constant()) {
1341
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1342
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1));
1343
0
                } else {
1344
0
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left;
1345
0
                    if (new_product > original_product) {
1346
0
                        throw_or_abort("bigfield: This should never happen");
1347
0
                    }
1348
0
                    maxval_updates.emplace_back(
1349
0
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1));
1350
0
                }
1351
0
            }
1352
0
        };
1353
1354
0
        auto compare_update_tuples = [](std::tuple<uint1024_t, size_t, size_t>& left_element,
1355
0
                                        std::tuple<uint1024_t, size_t, size_t>& right_element) {
1356
0
            return std::get<0>(left_element) > std::get<0>(right_element);
1357
0
        };
1358
1359
        // Now we loop through, reducing 1 element each time. This is costly in code, but allows us to use fewer
1360
        // gates
1361
1362
0
        while (reduction_required) {
1363
            // Compute the possible reduction updates
1364
0
            compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products);
1365
1366
            // Sort the vector, larger values first
1367
0
            std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples);
1368
1369
            // We choose the largest update
1370
0
            auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0];
1371
0
            if (!update_size) {
1372
0
                throw_or_abort("bigfield: Can't reduce further");
1373
0
            }
1374
            // Reduce the larger of the multiplicands that compose the product
1375
0
            if (multiplicand_index == 0) {
1376
0
                mul_left[largest_update_product_index].self_reduce();
1377
0
            } else {
1378
0
                mul_right[largest_update_product_index].self_reduce();
1379
0
            }
1380
1381
0
            for (size_t i = 0; i < number_of_products; i++) {
1382
0
                max_values_left[i] = mul_left[i].get_maximum_value();
1383
0
                max_values_right[i] = mul_right[i].get_maximum_value();
1384
0
            }
1385
0
            reduction_required = std::get<0>(
1386
0
                get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1387
0
        }
1388
1389
        // Now we have reduced everything exactly to the point of no overflow. There is probably a way to use even
1390
        // fewer reductions, but for now this will suffice.
1391
0
    }
1392
28.3k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_
Line
Count
Source
1275
2.23k
{
1276
2.23k
    ASSERT(mul_left.size() == mul_right.size());
1277
2.23k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1278
2.23k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1279
1280
2.23k
    const size_t number_of_products = mul_left.size();
1281
    // Get the maximum values of elements
1282
2.23k
    std::vector<uint512_t> max_values_left;
1283
2.23k
    std::vector<uint512_t> max_values_right;
1284
1285
2.23k
    max_values_left.reserve(number_of_products);
1286
2.23k
    max_values_right.reserve(number_of_products);
1287
    // Do regular reduction checks for all elements
1288
7.01k
    for (auto& left_element : mul_left) {
1289
7.01k
        left_element.reduction_check();
1290
7.01k
        max_values_left.emplace_back(left_element.get_maximum_value());
1291
7.01k
    }
1292
1293
7.01k
    for (auto& right_element : mul_right) {
1294
7.01k
        right_element.reduction_check();
1295
7.01k
        max_values_right.emplace_back(right_element.get_maximum_value());
1296
7.01k
    }
1297
1298
    // Perform CRT checks for the whole evaluation
1299
    // 1. Check if we can overflow CRT modulus
1300
    // 2. Check if the quotient actually fits in our range proof.
1301
    // 3. If we haven't passed one of the checks, reduce accordingly, starting with the largest product
1302
1303
    // We only get the bitlength of range proof if there is no reduction
1304
2.23k
    bool reduction_required;
1305
2.23k
    reduction_required = std::get<0>(
1306
2.23k
        get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1307
1308
2.23k
    if (reduction_required) {
1309
1310
        // We are out of luck and have to reduce the elements to keep the intermediate result below CRT modulus
1311
        // For that we need to compute the maximum update - how much reducing each element is going to update the
1312
        // quotient.
1313
        // Contents of the tuple: | Qmax_before-Qmax_after | product number | argument number |
1314
0
        std::vector<std::tuple<uint1024_t, size_t, size_t>> maximum_value_updates;
1315
1316
        // We use this lambda function before the loop and in the loop itself
1317
        // It computes the maximum value update from reduction of each element
1318
0
        auto compute_updates = [](std::vector<std::tuple<uint1024_t, size_t, size_t>>& maxval_updates,
1319
0
                                  std::vector<bigfield>& m_left,
1320
0
                                  std::vector<bigfield>& m_right,
1321
0
                                  size_t number_of_products) {
1322
0
            maxval_updates.resize(0);
1323
0
            maxval_updates.reserve(number_of_products * 2);
1324
            // Compute all reduction differences
1325
0
            for (size_t i = 0; i < number_of_products; i++) {
1326
0
                uint1024_t original_left = static_cast<uint1024_t>(m_left[i].get_maximum_value());
1327
0
                uint1024_t original_right = static_cast<uint1024_t>(m_right[i].get_maximum_value());
1328
0
                uint1024_t original_product = original_left * original_right;
1329
0
                if (m_left[i].is_constant()) {
1330
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1331
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 0));
1332
0
                } else {
1333
0
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_right;
1334
0
                    if (new_product > original_product) {
1335
0
                        throw_or_abort("bigfield: This should never happen");
1336
0
                    }
1337
0
                    maxval_updates.emplace_back(
1338
0
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 0));
1339
0
                }
1340
0
                if (m_right[i].is_constant()) {
1341
                    // If the multiplicand is constant, we can't reduce it, so the update is 0.
1342
0
                    maxval_updates.emplace_back(std::tuple<uint1024_t, size_t, size_t>(0, i, 1));
1343
0
                } else {
1344
0
                    uint1024_t new_product = DEFAULT_MAXIMUM_REMAINDER * original_left;
1345
0
                    if (new_product > original_product) {
1346
0
                        throw_or_abort("bigfield: This should never happen");
1347
0
                    }
1348
0
                    maxval_updates.emplace_back(
1349
0
                        std::tuple<uint1024_t, size_t, size_t>(original_product - new_product, i, 1));
1350
0
                }
1351
0
            }
1352
0
        };
1353
1354
0
        auto compare_update_tuples = [](std::tuple<uint1024_t, size_t, size_t>& left_element,
1355
0
                                        std::tuple<uint1024_t, size_t, size_t>& right_element) {
1356
0
            return std::get<0>(left_element) > std::get<0>(right_element);
1357
0
        };
1358
1359
        // Now we loop through, reducing 1 element each time. This is costly in code, but allows us to use fewer
1360
        // gates
1361
1362
0
        while (reduction_required) {
1363
            // Compute the possible reduction updates
1364
0
            compute_updates(maximum_value_updates, mul_left, mul_right, number_of_products);
1365
1366
            // Sort the vector, larger values first
1367
0
            std::sort(maximum_value_updates.begin(), maximum_value_updates.end(), compare_update_tuples);
1368
1369
            // We choose the largest update
1370
0
            auto [update_size, largest_update_product_index, multiplicand_index] = maximum_value_updates[0];
1371
0
            if (!update_size) {
1372
0
                throw_or_abort("bigfield: Can't reduce further");
1373
0
            }
1374
            // Reduce the larger of the multiplicands that compose the product
1375
0
            if (multiplicand_index == 0) {
1376
0
                mul_left[largest_update_product_index].self_reduce();
1377
0
            } else {
1378
0
                mul_right[largest_update_product_index].self_reduce();
1379
0
            }
1380
1381
0
            for (size_t i = 0; i < number_of_products; i++) {
1382
0
                max_values_left[i] = mul_left[i].get_maximum_value();
1383
0
                max_values_right[i] = mul_right[i].get_maximum_value();
1384
0
            }
1385
0
            reduction_required = std::get<0>(
1386
0
                get_quotient_reduction_info(max_values_left, max_values_right, to_add, { DEFAULT_MAXIMUM_REMAINDER }));
1387
0
        }
1388
1389
        // Now we have reduced everything exactly to the point of no overflow. There is probably a way to use even
1390
        // fewer reductions, but for now this will suffice.
1391
0
    }
1392
2.23k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS9_SaIS9_EESD_RKSC_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE32perform_reductions_for_mult_maddERSt6vectorIS6_SaIS6_EESA_RKS9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE32perform_reductions_for_mult_maddERSt6vectorIS8_SaIS8_EESC_RKSB_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E32perform_reductions_for_mult_maddERSt6vectorIS7_SaIS7_EESB_RKSA_
1393
1394
/**
1395
 * Evaluate the sum of products and additional values safely.
1396
 *
1397
 * @param mul_left Vector of bigfield multiplicands
1398
 * @param mul_right Vector of bigfield multipliers
1399
 * @param to_add Vector of bigfield elements to add to the sum of products
1400
 *
1401
 * @return A reduced value that is the sum of all products and to_add values
1402
 * */
1403
template <typename Builder, typename T>
1404
bigfield<Builder, T> bigfield<Builder, T>::mult_madd(const std::vector<bigfield>& mul_left,
1405
                                                     const std::vector<bigfield>& mul_right,
1406
                                                     const std::vector<bigfield>& to_add,
1407
                                                     bool fix_remainder_to_zero)
1408
370k
{
1409
370k
    ASSERT(mul_left.size() == mul_right.size());
1410
370k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1411
370k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1412
1413
0
    std::vector<bigfield> mutable_mul_left(mul_left);
1414
0
    std::vector<bigfield> mutable_mul_right(mul_right);
1415
1416
0
    const size_t number_of_products = mul_left.size();
1417
1418
0
    const uint1024_t modulus(target_basis.modulus);
1419
0
    uint1024_t worst_case_product_sum(0);
1420
0
    uint1024_t add_right_constant_sum(0);
1421
1422
    // First we do all constant optimizations
1423
0
    bool add_constant = true;
1424
0
    std::vector<bigfield> new_to_add;
1425
1426
0
    OriginTag new_tag{};
1427
    // Merge all tags. Do it in pairs (logically a submitted value can be masked by a challenge)
1428
824k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1429
824k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1430
824k
    }
1431
653k
    for (auto& element : to_add) {
1432
653k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1433
653k
    }
1434
1435
653k
    for (const auto& add_element : to_add) {
1436
653k
        add_element.reduction_check();
1437
653k
        if (add_element.is_constant()) {
1438
86
            add_right_constant_sum += uint1024_t(add_element.get_value());
1439
653k
        } else {
1440
653k
            add_constant = false;
1441
653k
            new_to_add.push_back(add_element);
1442
653k
        }
1443
653k
    }
1444
1445
    // Compute the product sum
1446
    // Optimize constant use
1447
0
    uint1024_t sum_of_constant_products(0);
1448
0
    std::vector<bigfield> new_input_left;
1449
0
    std::vector<bigfield> new_input_right;
1450
0
    bool product_sum_constant = true;
1451
1.19M
    for (size_t i = 0; i < number_of_products; i++) {
1452
824k
        if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) {
1453
            // If constant, just add to the sum
1454
0
            sum_of_constant_products +=
1455
0
                uint1024_t(mutable_mul_left[i].get_value()) * uint1024_t(mutable_mul_right[i].get_value());
1456
824k
        } else {
1457
            // If not, add to nonconstant sum and remember the elements
1458
824k
            new_input_left.push_back(mutable_mul_left[i]);
1459
824k
            new_input_right.push_back(mutable_mul_right[i]);
1460
824k
            product_sum_constant = false;
1461
824k
        }
1462
824k
    }
1463
1464
0
    Builder* ctx = nullptr;
1465
    // Search through all multiplicands on the left
1466
370k
    for (auto& el : mutable_mul_left) {
1467
370k
        if (el.context) {
1468
370k
            ctx = el.context;
1469
370k
            break;
1470
370k
        }
1471
370k
    }
1472
    // And on the right
1473
370k
    if (!ctx) {
1474
1
        for (auto& el : mutable_mul_right) {
1475
0
            if (el.context) {
1476
0
                ctx = el.context;
1477
0
                break;
1478
0
            }
1479
0
        }
1480
1
    }
1481
370k
    if (product_sum_constant) {
1482
1
        if (add_constant) {
1483
            // Simply return the constant, no need unsafe_multiply_add
1484
1
            const auto [quotient_1024, remainder_1024] =
1485
1
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1486
1
            ASSERT(!fix_remainder_to_zero || remainder_1024 == 0);
1487
0
            auto result = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1488
0
            result.set_origin_tag(new_tag);
1489
0
            return result;
1490
1
        } else {
1491
0
            const auto [quotient_1024, remainder_1024] =
1492
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1493
0
            uint256_t remainder_value = remainder_1024.lo.lo;
1494
0
            bigfield result;
1495
0
            if (remainder_value == uint256_t(0)) {
1496
                // No need to add extra term to new_to_add
1497
0
                result = sum(new_to_add);
1498
0
            } else {
1499
                // Add the constant term
1500
0
                new_to_add.push_back(bigfield(ctx, uint256_t(remainder_value)));
1501
0
                result = sum(new_to_add);
1502
0
            }
1503
0
            if (fix_remainder_to_zero) {
1504
0
                result.self_reduce();
1505
0
                result.assert_equal(zero());
1506
0
            }
1507
0
            result.set_origin_tag(new_tag);
1508
0
            return result;
1509
0
        }
1510
1
    }
1511
1512
    // Now that we know that there is at least 1 non-constant multiplication, we can start estimating reductions,
1513
    // etc
1514
1515
    // Compute the constant term we're adding
1516
370k
    const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1517
370k
    const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo;
1518
1519
370k
    if (constant_part_remainder_256 != uint256_t(0)) {
1520
86
        new_to_add.push_back(bigfield(ctx, constant_part_remainder_256));
1521
86
    }
1522
    // Compute added sum
1523
370k
    uint1024_t add_right_final_sum(0);
1524
370k
    uint1024_t add_right_maximum(0);
1525
653k
    for (const auto& add_element : new_to_add) {
1526
        // Technically not needed, but better to leave just in case
1527
653k
        add_element.reduction_check();
1528
653k
        add_right_final_sum += uint1024_t(add_element.get_value());
1529
1530
653k
        add_right_maximum += uint1024_t(add_element.get_maximum_value());
1531
653k
    }
1532
370k
    const size_t final_number_of_products = new_input_left.size();
1533
1534
    // We need to check if it is possible to reduce the products enough
1535
370k
    worst_case_product_sum = uint1024_t(final_number_of_products) * uint1024_t(DEFAULT_MAXIMUM_REMAINDER) *
1536
370k
                             uint1024_t(DEFAULT_MAXIMUM_REMAINDER);
1537
1538
    // Check that we can actually reduce the products enough, this assert will probably never get triggered
1539
370k
    ASSERT((worst_case_product_sum + add_right_maximum) < get_maximum_crt_product());
1540
1541
    // We've collapsed all constants, checked if we can compute the sum of products in the worst case, time to check
1542
    // if we need to reduce something
1543
0
    perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add);
1544
0
    uint1024_t sum_of_products_final(0);
1545
1.19M
    for (size_t i = 0; i < final_number_of_products; i++) {
1546
824k
        sum_of_products_final += uint1024_t(new_input_left[i].get_value()) * uint1024_t(new_input_right[i].get_value());
1547
824k
    }
1548
1549
    // Get the number of range proof bits for the quotient
1550
0
    const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER });
1551
1552
    // Compute the quotient and remainder
1553
0
    const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus);
1554
1555
    // If we are establishing an identity and the remainder has to be zero, we need to check, that it actually is
1556
1557
370k
    if (fix_remainder_to_zero) {
1558
        // This is not the only check. Circuit check is coming later :)
1559
341k
        ASSERT(remainder_1024.lo == uint512_t(0));
1560
341k
    }
1561
0
    const uint512_t quotient_value = quotient_1024.lo;
1562
0
    const uint512_t remainder_value = remainder_1024.lo;
1563
1564
0
    bigfield remainder;
1565
0
    bigfield quotient;
1566
    // Constrain quotient to mitigate CRT overflow attacks
1567
0
    quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1568
1569
370k
    if (fix_remainder_to_zero) {
1570
341k
        remainder = zero();
1571
        // remainder needs to be defined as wire value and not selector values to satisfy
1572
        // Ultra's bigfield custom gates
1573
341k
        remainder.convert_constant_to_fixed_witness(ctx);
1574
341k
    } else {
1575
28.6k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1576
28.6k
    }
1577
1578
0
    unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder });
1579
1580
0
    remainder.set_origin_tag(new_tag);
1581
0
    return remainder;
1582
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE9mult_maddERKSt6vectorIS6_SaIS6_EESB_SB_b
Line
Count
Source
1408
338k
{
1409
338k
    ASSERT(mul_left.size() == mul_right.size());
1410
338k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1411
338k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1412
1413
338k
    std::vector<bigfield> mutable_mul_left(mul_left);
1414
338k
    std::vector<bigfield> mutable_mul_right(mul_right);
1415
1416
338k
    const size_t number_of_products = mul_left.size();
1417
1418
338k
    const uint1024_t modulus(target_basis.modulus);
1419
338k
    uint1024_t worst_case_product_sum(0);
1420
338k
    uint1024_t add_right_constant_sum(0);
1421
1422
    // First we do all constant optimizations
1423
338k
    bool add_constant = true;
1424
338k
    std::vector<bigfield> new_to_add;
1425
1426
338k
    OriginTag new_tag{};
1427
    // Merge all tags. Do it in pairs (logically a submitted value can be masked by a challenge)
1428
743k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1429
743k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1430
743k
    }
1431
615k
    for (auto& element : to_add) {
1432
615k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1433
615k
    }
1434
1435
615k
    for (const auto& add_element : to_add) {
1436
615k
        add_element.reduction_check();
1437
615k
        if (add_element.is_constant()) {
1438
79
            add_right_constant_sum += uint1024_t(add_element.get_value());
1439
615k
        } else {
1440
615k
            add_constant = false;
1441
615k
            new_to_add.push_back(add_element);
1442
615k
        }
1443
615k
    }
1444
1445
    // Compute the product sum
1446
    // Optimize constant use
1447
338k
    uint1024_t sum_of_constant_products(0);
1448
338k
    std::vector<bigfield> new_input_left;
1449
338k
    std::vector<bigfield> new_input_right;
1450
338k
    bool product_sum_constant = true;
1451
1.08M
    for (size_t i = 0; i < number_of_products; i++) {
1452
743k
        if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) {
1453
            // If constant, just add to the sum
1454
0
            sum_of_constant_products +=
1455
0
                uint1024_t(mutable_mul_left[i].get_value()) * uint1024_t(mutable_mul_right[i].get_value());
1456
743k
        } else {
1457
            // If not, add to nonconstant sum and remember the elements
1458
743k
            new_input_left.push_back(mutable_mul_left[i]);
1459
743k
            new_input_right.push_back(mutable_mul_right[i]);
1460
743k
            product_sum_constant = false;
1461
743k
        }
1462
743k
    }
1463
1464
338k
    Builder* ctx = nullptr;
1465
    // Search through all multiplicands on the left
1466
338k
    for (auto& el : mutable_mul_left) {
1467
338k
        if (el.context) {
1468
338k
            ctx = el.context;
1469
338k
            break;
1470
338k
        }
1471
338k
    }
1472
    // And on the right
1473
338k
    if (!ctx) {
1474
1
        for (auto& el : mutable_mul_right) {
1475
0
            if (el.context) {
1476
0
                ctx = el.context;
1477
0
                break;
1478
0
            }
1479
0
        }
1480
1
    }
1481
338k
    if (product_sum_constant) {
1482
1
        if (add_constant) {
1483
            // Simply return the constant, no need unsafe_multiply_add
1484
1
            const auto [quotient_1024, remainder_1024] =
1485
1
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1486
1
            ASSERT(!fix_remainder_to_zero || remainder_1024 == 0);
1487
1
            auto result = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1488
1
            result.set_origin_tag(new_tag);
1489
1
            return result;
1490
1
        } else {
1491
0
            const auto [quotient_1024, remainder_1024] =
1492
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1493
0
            uint256_t remainder_value = remainder_1024.lo.lo;
1494
0
            bigfield result;
1495
0
            if (remainder_value == uint256_t(0)) {
1496
                // No need to add extra term to new_to_add
1497
0
                result = sum(new_to_add);
1498
0
            } else {
1499
                // Add the constant term
1500
0
                new_to_add.push_back(bigfield(ctx, uint256_t(remainder_value)));
1501
0
                result = sum(new_to_add);
1502
0
            }
1503
0
            if (fix_remainder_to_zero) {
1504
0
                result.self_reduce();
1505
0
                result.assert_equal(zero());
1506
0
            }
1507
0
            result.set_origin_tag(new_tag);
1508
0
            return result;
1509
0
        }
1510
1
    }
1511
1512
    // Now that we know that there is at least 1 non-constant multiplication, we can start estimating reductions,
1513
    // etc
1514
1515
    // Compute the constant term we're adding
1516
338k
    const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1517
338k
    const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo;
1518
1519
338k
    if (constant_part_remainder_256 != uint256_t(0)) {
1520
79
        new_to_add.push_back(bigfield(ctx, constant_part_remainder_256));
1521
79
    }
1522
    // Compute added sum
1523
338k
    uint1024_t add_right_final_sum(0);
1524
338k
    uint1024_t add_right_maximum(0);
1525
615k
    for (const auto& add_element : new_to_add) {
1526
        // Technically not needed, but better to leave just in case
1527
615k
        add_element.reduction_check();
1528
615k
        add_right_final_sum += uint1024_t(add_element.get_value());
1529
1530
615k
        add_right_maximum += uint1024_t(add_element.get_maximum_value());
1531
615k
    }
1532
338k
    const size_t final_number_of_products = new_input_left.size();
1533
1534
    // We need to check if it is possible to reduce the products enough
1535
338k
    worst_case_product_sum = uint1024_t(final_number_of_products) * uint1024_t(DEFAULT_MAXIMUM_REMAINDER) *
1536
338k
                             uint1024_t(DEFAULT_MAXIMUM_REMAINDER);
1537
1538
    // Check that we can actually reduce the products enough, this assert will probably never get triggered
1539
338k
    ASSERT((worst_case_product_sum + add_right_maximum) < get_maximum_crt_product());
1540
1541
    // We've collapsed all constants, checked if we can compute the sum of products in the worst case, time to check
1542
    // if we need to reduce something
1543
338k
    perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add);
1544
338k
    uint1024_t sum_of_products_final(0);
1545
1.08M
    for (size_t i = 0; i < final_number_of_products; i++) {
1546
743k
        sum_of_products_final += uint1024_t(new_input_left[i].get_value()) * uint1024_t(new_input_right[i].get_value());
1547
743k
    }
1548
1549
    // Get the number of range proof bits for the quotient
1550
338k
    const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER });
1551
1552
    // Compute the quotient and remainder
1553
338k
    const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus);
1554
1555
    // If we are establishing an identity and the remainder has to be zero, we need to check, that it actually is
1556
1557
338k
    if (fix_remainder_to_zero) {
1558
        // This is not the only check. Circuit check is coming later :)
1559
314k
        ASSERT(remainder_1024.lo == uint512_t(0));
1560
314k
    }
1561
338k
    const uint512_t quotient_value = quotient_1024.lo;
1562
338k
    const uint512_t remainder_value = remainder_1024.lo;
1563
1564
338k
    bigfield remainder;
1565
338k
    bigfield quotient;
1566
    // Constrain quotient to mitigate CRT overflow attacks
1567
338k
    quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1568
1569
338k
    if (fix_remainder_to_zero) {
1570
314k
        remainder = zero();
1571
        // remainder needs to be defined as wire value and not selector values to satisfy
1572
        // Ultra's bigfield custom gates
1573
314k
        remainder.convert_constant_to_fixed_witness(ctx);
1574
314k
    } else {
1575
23.5k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1576
23.5k
    }
1577
1578
338k
    unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder });
1579
1580
338k
    remainder.set_origin_tag(new_tag);
1581
338k
    return remainder;
1582
338k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE9mult_maddERKSt6vectorIS6_SaIS6_EESB_SB_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE9mult_maddERKSt6vectorIS8_SaIS8_EESD_SD_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b
Line
Count
Source
1408
1.29k
{
1409
1.29k
    ASSERT(mul_left.size() == mul_right.size());
1410
1.29k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1411
1.29k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1412
1413
1.29k
    std::vector<bigfield> mutable_mul_left(mul_left);
1414
1.29k
    std::vector<bigfield> mutable_mul_right(mul_right);
1415
1416
1.29k
    const size_t number_of_products = mul_left.size();
1417
1418
1.29k
    const uint1024_t modulus(target_basis.modulus);
1419
1.29k
    uint1024_t worst_case_product_sum(0);
1420
1.29k
    uint1024_t add_right_constant_sum(0);
1421
1422
    // First we do all constant optimizations
1423
1.29k
    bool add_constant = true;
1424
1.29k
    std::vector<bigfield> new_to_add;
1425
1426
1.29k
    OriginTag new_tag{};
1427
    // Merge all tags. Do it in pairs (logically a submitted value can be masked by a challenge)
1428
3.15k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1429
3.15k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1430
3.15k
    }
1431
1.37k
    for (auto& element : to_add) {
1432
1.37k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1433
1.37k
    }
1434
1435
1.37k
    for (const auto& add_element : to_add) {
1436
1.37k
        add_element.reduction_check();
1437
1.37k
        if (add_element.is_constant()) {
1438
3
            add_right_constant_sum += uint1024_t(add_element.get_value());
1439
1.37k
        } else {
1440
1.37k
            add_constant = false;
1441
1.37k
            new_to_add.push_back(add_element);
1442
1.37k
        }
1443
1.37k
    }
1444
1445
    // Compute the product sum
1446
    // Optimize constant use
1447
1.29k
    uint1024_t sum_of_constant_products(0);
1448
1.29k
    std::vector<bigfield> new_input_left;
1449
1.29k
    std::vector<bigfield> new_input_right;
1450
1.29k
    bool product_sum_constant = true;
1451
4.44k
    for (size_t i = 0; i < number_of_products; i++) {
1452
3.15k
        if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) {
1453
            // If constant, just add to the sum
1454
0
            sum_of_constant_products +=
1455
0
                uint1024_t(mutable_mul_left[i].get_value()) * uint1024_t(mutable_mul_right[i].get_value());
1456
3.15k
        } else {
1457
            // If not, add to nonconstant sum and remember the elements
1458
3.15k
            new_input_left.push_back(mutable_mul_left[i]);
1459
3.15k
            new_input_right.push_back(mutable_mul_right[i]);
1460
3.15k
            product_sum_constant = false;
1461
3.15k
        }
1462
3.15k
    }
1463
1464
1.29k
    Builder* ctx = nullptr;
1465
    // Search through all multiplicands on the left
1466
1.29k
    for (auto& el : mutable_mul_left) {
1467
1.29k
        if (el.context) {
1468
1.29k
            ctx = el.context;
1469
1.29k
            break;
1470
1.29k
        }
1471
1.29k
    }
1472
    // And on the right
1473
1.29k
    if (!ctx) {
1474
0
        for (auto& el : mutable_mul_right) {
1475
0
            if (el.context) {
1476
0
                ctx = el.context;
1477
0
                break;
1478
0
            }
1479
0
        }
1480
0
    }
1481
1.29k
    if (product_sum_constant) {
1482
0
        if (add_constant) {
1483
            // Simply return the constant, no need unsafe_multiply_add
1484
0
            const auto [quotient_1024, remainder_1024] =
1485
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1486
0
            ASSERT(!fix_remainder_to_zero || remainder_1024 == 0);
1487
0
            auto result = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1488
0
            result.set_origin_tag(new_tag);
1489
0
            return result;
1490
0
        } else {
1491
0
            const auto [quotient_1024, remainder_1024] =
1492
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1493
0
            uint256_t remainder_value = remainder_1024.lo.lo;
1494
0
            bigfield result;
1495
0
            if (remainder_value == uint256_t(0)) {
1496
                // No need to add extra term to new_to_add
1497
0
                result = sum(new_to_add);
1498
0
            } else {
1499
                // Add the constant term
1500
0
                new_to_add.push_back(bigfield(ctx, uint256_t(remainder_value)));
1501
0
                result = sum(new_to_add);
1502
0
            }
1503
0
            if (fix_remainder_to_zero) {
1504
0
                result.self_reduce();
1505
0
                result.assert_equal(zero());
1506
0
            }
1507
0
            result.set_origin_tag(new_tag);
1508
0
            return result;
1509
0
        }
1510
0
    }
1511
1512
    // Now that we know that there is at least 1 non-constant multiplication, we can start estimating reductions,
1513
    // etc
1514
1515
    // Compute the constant term we're adding
1516
1.29k
    const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1517
1.29k
    const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo;
1518
1519
1.29k
    if (constant_part_remainder_256 != uint256_t(0)) {
1520
3
        new_to_add.push_back(bigfield(ctx, constant_part_remainder_256));
1521
3
    }
1522
    // Compute added sum
1523
1.29k
    uint1024_t add_right_final_sum(0);
1524
1.29k
    uint1024_t add_right_maximum(0);
1525
1.37k
    for (const auto& add_element : new_to_add) {
1526
        // Technically not needed, but better to leave just in case
1527
1.37k
        add_element.reduction_check();
1528
1.37k
        add_right_final_sum += uint1024_t(add_element.get_value());
1529
1530
1.37k
        add_right_maximum += uint1024_t(add_element.get_maximum_value());
1531
1.37k
    }
1532
1.29k
    const size_t final_number_of_products = new_input_left.size();
1533
1534
    // We need to check if it is possible to reduce the products enough
1535
1.29k
    worst_case_product_sum = uint1024_t(final_number_of_products) * uint1024_t(DEFAULT_MAXIMUM_REMAINDER) *
1536
1.29k
                             uint1024_t(DEFAULT_MAXIMUM_REMAINDER);
1537
1538
    // Check that we can actually reduce the products enough, this assert will probably never get triggered
1539
1.29k
    ASSERT((worst_case_product_sum + add_right_maximum) < get_maximum_crt_product());
1540
1541
    // We've collapsed all constants, checked if we can compute the sum of products in the worst case, time to check
1542
    // if we need to reduce something
1543
1.29k
    perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add);
1544
1.29k
    uint1024_t sum_of_products_final(0);
1545
4.44k
    for (size_t i = 0; i < final_number_of_products; i++) {
1546
3.15k
        sum_of_products_final += uint1024_t(new_input_left[i].get_value()) * uint1024_t(new_input_right[i].get_value());
1547
3.15k
    }
1548
1549
    // Get the number of range proof bits for the quotient
1550
1.29k
    const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER });
1551
1552
    // Compute the quotient and remainder
1553
1.29k
    const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus);
1554
1555
    // If we are establishing an identity and the remainder has to be zero, we need to check, that it actually is
1556
1557
1.29k
    if (fix_remainder_to_zero) {
1558
        // This is not the only check. Circuit check is coming later :)
1559
1.09k
        ASSERT(remainder_1024.lo == uint512_t(0));
1560
1.09k
    }
1561
1.29k
    const uint512_t quotient_value = quotient_1024.lo;
1562
1.29k
    const uint512_t remainder_value = remainder_1024.lo;
1563
1564
1.29k
    bigfield remainder;
1565
1.29k
    bigfield quotient;
1566
    // Constrain quotient to mitigate CRT overflow attacks
1567
1.29k
    quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1568
1569
1.29k
    if (fix_remainder_to_zero) {
1570
1.09k
        remainder = zero();
1571
        // remainder needs to be defined as wire value and not selector values to satisfy
1572
        // Ultra's bigfield custom gates
1573
1.09k
        remainder.convert_constant_to_fixed_witness(ctx);
1574
1.09k
    } else {
1575
192
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1576
192
    }
1577
1578
1.29k
    unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder });
1579
1580
1.29k
    remainder.set_origin_tag(new_tag);
1581
1.29k
    return remainder;
1582
1.29k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE9mult_maddERKSt6vectorIS9_SaIS9_EESE_SE_b
Line
Count
Source
1408
28.3k
{
1409
28.3k
    ASSERT(mul_left.size() == mul_right.size());
1410
28.3k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1411
28.3k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1412
1413
28.3k
    std::vector<bigfield> mutable_mul_left(mul_left);
1414
28.3k
    std::vector<bigfield> mutable_mul_right(mul_right);
1415
1416
28.3k
    const size_t number_of_products = mul_left.size();
1417
1418
28.3k
    const uint1024_t modulus(target_basis.modulus);
1419
28.3k
    uint1024_t worst_case_product_sum(0);
1420
28.3k
    uint1024_t add_right_constant_sum(0);
1421
1422
    // First we do all constant optimizations
1423
28.3k
    bool add_constant = true;
1424
28.3k
    std::vector<bigfield> new_to_add;
1425
1426
28.3k
    OriginTag new_tag{};
1427
    // Merge all tags. Do it in pairs (logically a submitted value can be masked by a challenge)
1428
70.5k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1429
70.5k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1430
70.5k
    }
1431
33.1k
    for (auto& element : to_add) {
1432
33.1k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1433
33.1k
    }
1434
1435
33.1k
    for (const auto& add_element : to_add) {
1436
33.1k
        add_element.reduction_check();
1437
33.1k
        if (add_element.is_constant()) {
1438
0
            add_right_constant_sum += uint1024_t(add_element.get_value());
1439
33.1k
        } else {
1440
33.1k
            add_constant = false;
1441
33.1k
            new_to_add.push_back(add_element);
1442
33.1k
        }
1443
33.1k
    }
1444
1445
    // Compute the product sum
1446
    // Optimize constant use
1447
28.3k
    uint1024_t sum_of_constant_products(0);
1448
28.3k
    std::vector<bigfield> new_input_left;
1449
28.3k
    std::vector<bigfield> new_input_right;
1450
28.3k
    bool product_sum_constant = true;
1451
98.9k
    for (size_t i = 0; i < number_of_products; i++) {
1452
70.5k
        if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) {
1453
            // If constant, just add to the sum
1454
0
            sum_of_constant_products +=
1455
0
                uint1024_t(mutable_mul_left[i].get_value()) * uint1024_t(mutable_mul_right[i].get_value());
1456
70.5k
        } else {
1457
            // If not, add to nonconstant sum and remember the elements
1458
70.5k
            new_input_left.push_back(mutable_mul_left[i]);
1459
70.5k
            new_input_right.push_back(mutable_mul_right[i]);
1460
70.5k
            product_sum_constant = false;
1461
70.5k
        }
1462
70.5k
    }
1463
1464
28.3k
    Builder* ctx = nullptr;
1465
    // Search through all multiplicands on the left
1466
28.3k
    for (auto& el : mutable_mul_left) {
1467
28.3k
        if (el.context) {
1468
28.3k
            ctx = el.context;
1469
28.3k
            break;
1470
28.3k
        }
1471
28.3k
    }
1472
    // And on the right
1473
28.3k
    if (!ctx) {
1474
0
        for (auto& el : mutable_mul_right) {
1475
0
            if (el.context) {
1476
0
                ctx = el.context;
1477
0
                break;
1478
0
            }
1479
0
        }
1480
0
    }
1481
28.3k
    if (product_sum_constant) {
1482
0
        if (add_constant) {
1483
            // Simply return the constant, no need unsafe_multiply_add
1484
0
            const auto [quotient_1024, remainder_1024] =
1485
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1486
0
            ASSERT(!fix_remainder_to_zero || remainder_1024 == 0);
1487
0
            auto result = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1488
0
            result.set_origin_tag(new_tag);
1489
0
            return result;
1490
0
        } else {
1491
0
            const auto [quotient_1024, remainder_1024] =
1492
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1493
0
            uint256_t remainder_value = remainder_1024.lo.lo;
1494
0
            bigfield result;
1495
0
            if (remainder_value == uint256_t(0)) {
1496
                // No need to add extra term to new_to_add
1497
0
                result = sum(new_to_add);
1498
0
            } else {
1499
                // Add the constant term
1500
0
                new_to_add.push_back(bigfield(ctx, uint256_t(remainder_value)));
1501
0
                result = sum(new_to_add);
1502
0
            }
1503
0
            if (fix_remainder_to_zero) {
1504
0
                result.self_reduce();
1505
0
                result.assert_equal(zero());
1506
0
            }
1507
0
            result.set_origin_tag(new_tag);
1508
0
            return result;
1509
0
        }
1510
0
    }
1511
1512
    // Now that we know that there is at least 1 non-constant multiplication, we can start estimating reductions,
1513
    // etc
1514
1515
    // Compute the constant term we're adding
1516
28.3k
    const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1517
28.3k
    const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo;
1518
1519
28.3k
    if (constant_part_remainder_256 != uint256_t(0)) {
1520
0
        new_to_add.push_back(bigfield(ctx, constant_part_remainder_256));
1521
0
    }
1522
    // Compute added sum
1523
28.3k
    uint1024_t add_right_final_sum(0);
1524
28.3k
    uint1024_t add_right_maximum(0);
1525
33.1k
    for (const auto& add_element : new_to_add) {
1526
        // Technically not needed, but better to leave just in case
1527
33.1k
        add_element.reduction_check();
1528
33.1k
        add_right_final_sum += uint1024_t(add_element.get_value());
1529
1530
33.1k
        add_right_maximum += uint1024_t(add_element.get_maximum_value());
1531
33.1k
    }
1532
28.3k
    const size_t final_number_of_products = new_input_left.size();
1533
1534
    // We need to check if it is possible to reduce the products enough
1535
28.3k
    worst_case_product_sum = uint1024_t(final_number_of_products) * uint1024_t(DEFAULT_MAXIMUM_REMAINDER) *
1536
28.3k
                             uint1024_t(DEFAULT_MAXIMUM_REMAINDER);
1537
1538
    // Check that we can actually reduce the products enough, this assert will probably never get triggered
1539
28.3k
    ASSERT((worst_case_product_sum + add_right_maximum) < get_maximum_crt_product());
1540
1541
    // We've collapsed all constants, checked if we can compute the sum of products in the worst case, time to check
1542
    // if we need to reduce something
1543
28.3k
    perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add);
1544
28.3k
    uint1024_t sum_of_products_final(0);
1545
98.9k
    for (size_t i = 0; i < final_number_of_products; i++) {
1546
70.5k
        sum_of_products_final += uint1024_t(new_input_left[i].get_value()) * uint1024_t(new_input_right[i].get_value());
1547
70.5k
    }
1548
1549
    // Get the number of range proof bits for the quotient
1550
28.3k
    const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER });
1551
1552
    // Compute the quotient and remainder
1553
28.3k
    const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus);
1554
1555
    // If we are establishing an identity and the remainder has to be zero, we need to check, that it actually is
1556
1557
28.3k
    if (fix_remainder_to_zero) {
1558
        // This is not the only check. Circuit check is coming later :)
1559
23.7k
        ASSERT(remainder_1024.lo == uint512_t(0));
1560
23.7k
    }
1561
28.3k
    const uint512_t quotient_value = quotient_1024.lo;
1562
28.3k
    const uint512_t remainder_value = remainder_1024.lo;
1563
1564
28.3k
    bigfield remainder;
1565
28.3k
    bigfield quotient;
1566
    // Constrain quotient to mitigate CRT overflow attacks
1567
28.3k
    quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1568
1569
28.3k
    if (fix_remainder_to_zero) {
1570
23.7k
        remainder = zero();
1571
        // remainder needs to be defined as wire value and not selector values to satisfy
1572
        // Ultra's bigfield custom gates
1573
23.7k
        remainder.convert_constant_to_fixed_witness(ctx);
1574
23.7k
    } else {
1575
4.60k
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1576
4.60k
    }
1577
1578
28.3k
    unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder });
1579
1580
28.3k
    remainder.set_origin_tag(new_tag);
1581
28.3k
    return remainder;
1582
28.3k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE9mult_maddERKSt6vectorIS9_SaIS9_EESE_SE_b
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b
Line
Count
Source
1408
2.23k
{
1409
2.23k
    ASSERT(mul_left.size() == mul_right.size());
1410
2.23k
    ASSERT(mul_left.size() <= MAXIMUM_SUMMAND_COUNT);
1411
2.23k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1412
1413
2.23k
    std::vector<bigfield> mutable_mul_left(mul_left);
1414
2.23k
    std::vector<bigfield> mutable_mul_right(mul_right);
1415
1416
2.23k
    const size_t number_of_products = mul_left.size();
1417
1418
2.23k
    const uint1024_t modulus(target_basis.modulus);
1419
2.23k
    uint1024_t worst_case_product_sum(0);
1420
2.23k
    uint1024_t add_right_constant_sum(0);
1421
1422
    // First we do all constant optimizations
1423
2.23k
    bool add_constant = true;
1424
2.23k
    std::vector<bigfield> new_to_add;
1425
1426
2.23k
    OriginTag new_tag{};
1427
    // Merge all tags. Do it in pairs (logically a submitted value can be masked by a challenge)
1428
7.01k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1429
7.01k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1430
7.01k
    }
1431
3.19k
    for (auto& element : to_add) {
1432
3.19k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1433
3.19k
    }
1434
1435
3.19k
    for (const auto& add_element : to_add) {
1436
3.19k
        add_element.reduction_check();
1437
3.19k
        if (add_element.is_constant()) {
1438
4
            add_right_constant_sum += uint1024_t(add_element.get_value());
1439
3.18k
        } else {
1440
3.18k
            add_constant = false;
1441
3.18k
            new_to_add.push_back(add_element);
1442
3.18k
        }
1443
3.19k
    }
1444
1445
    // Compute the product sum
1446
    // Optimize constant use
1447
2.23k
    uint1024_t sum_of_constant_products(0);
1448
2.23k
    std::vector<bigfield> new_input_left;
1449
2.23k
    std::vector<bigfield> new_input_right;
1450
2.23k
    bool product_sum_constant = true;
1451
9.24k
    for (size_t i = 0; i < number_of_products; i++) {
1452
7.01k
        if (mutable_mul_left[i].is_constant() && mutable_mul_right[i].is_constant()) {
1453
            // If constant, just add to the sum
1454
0
            sum_of_constant_products +=
1455
0
                uint1024_t(mutable_mul_left[i].get_value()) * uint1024_t(mutable_mul_right[i].get_value());
1456
7.01k
        } else {
1457
            // If not, add to nonconstant sum and remember the elements
1458
7.01k
            new_input_left.push_back(mutable_mul_left[i]);
1459
7.01k
            new_input_right.push_back(mutable_mul_right[i]);
1460
7.01k
            product_sum_constant = false;
1461
7.01k
        }
1462
7.01k
    }
1463
1464
2.23k
    Builder* ctx = nullptr;
1465
    // Search through all multiplicands on the left
1466
2.23k
    for (auto& el : mutable_mul_left) {
1467
2.23k
        if (el.context) {
1468
2.23k
            ctx = el.context;
1469
2.23k
            break;
1470
2.23k
        }
1471
2.23k
    }
1472
    // And on the right
1473
2.23k
    if (!ctx) {
1474
0
        for (auto& el : mutable_mul_right) {
1475
0
            if (el.context) {
1476
0
                ctx = el.context;
1477
0
                break;
1478
0
            }
1479
0
        }
1480
0
    }
1481
2.23k
    if (product_sum_constant) {
1482
0
        if (add_constant) {
1483
            // Simply return the constant, no need unsafe_multiply_add
1484
0
            const auto [quotient_1024, remainder_1024] =
1485
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1486
0
            ASSERT(!fix_remainder_to_zero || remainder_1024 == 0);
1487
0
            auto result = bigfield(ctx, uint256_t(remainder_1024.lo.lo));
1488
0
            result.set_origin_tag(new_tag);
1489
0
            return result;
1490
0
        } else {
1491
0
            const auto [quotient_1024, remainder_1024] =
1492
0
                (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1493
0
            uint256_t remainder_value = remainder_1024.lo.lo;
1494
0
            bigfield result;
1495
0
            if (remainder_value == uint256_t(0)) {
1496
                // No need to add extra term to new_to_add
1497
0
                result = sum(new_to_add);
1498
0
            } else {
1499
                // Add the constant term
1500
0
                new_to_add.push_back(bigfield(ctx, uint256_t(remainder_value)));
1501
0
                result = sum(new_to_add);
1502
0
            }
1503
0
            if (fix_remainder_to_zero) {
1504
0
                result.self_reduce();
1505
0
                result.assert_equal(zero());
1506
0
            }
1507
0
            result.set_origin_tag(new_tag);
1508
0
            return result;
1509
0
        }
1510
0
    }
1511
1512
    // Now that we know that there is at least 1 non-constant multiplication, we can start estimating reductions,
1513
    // etc
1514
1515
    // Compute the constant term we're adding
1516
2.23k
    const auto [_, constant_part_remainder_1024] = (sum_of_constant_products + add_right_constant_sum).divmod(modulus);
1517
2.23k
    const uint256_t constant_part_remainder_256 = constant_part_remainder_1024.lo.lo;
1518
1519
2.23k
    if (constant_part_remainder_256 != uint256_t(0)) {
1520
4
        new_to_add.push_back(bigfield(ctx, constant_part_remainder_256));
1521
4
    }
1522
    // Compute added sum
1523
2.23k
    uint1024_t add_right_final_sum(0);
1524
2.23k
    uint1024_t add_right_maximum(0);
1525
3.19k
    for (const auto& add_element : new_to_add) {
1526
        // Technically not needed, but better to leave just in case
1527
3.19k
        add_element.reduction_check();
1528
3.19k
        add_right_final_sum += uint1024_t(add_element.get_value());
1529
1530
3.19k
        add_right_maximum += uint1024_t(add_element.get_maximum_value());
1531
3.19k
    }
1532
2.23k
    const size_t final_number_of_products = new_input_left.size();
1533
1534
    // We need to check if it is possible to reduce the products enough
1535
2.23k
    worst_case_product_sum = uint1024_t(final_number_of_products) * uint1024_t(DEFAULT_MAXIMUM_REMAINDER) *
1536
2.23k
                             uint1024_t(DEFAULT_MAXIMUM_REMAINDER);
1537
1538
    // Check that we can actually reduce the products enough, this assert will probably never get triggered
1539
2.23k
    ASSERT((worst_case_product_sum + add_right_maximum) < get_maximum_crt_product());
1540
1541
    // We've collapsed all constants, checked if we can compute the sum of products in the worst case, time to check
1542
    // if we need to reduce something
1543
2.23k
    perform_reductions_for_mult_madd(new_input_left, new_input_right, new_to_add);
1544
2.23k
    uint1024_t sum_of_products_final(0);
1545
9.24k
    for (size_t i = 0; i < final_number_of_products; i++) {
1546
7.01k
        sum_of_products_final += uint1024_t(new_input_left[i].get_value()) * uint1024_t(new_input_right[i].get_value());
1547
7.01k
    }
1548
1549
    // Get the number of range proof bits for the quotient
1550
2.23k
    const size_t num_quotient_bits = get_quotient_max_bits({ DEFAULT_MAXIMUM_REMAINDER });
1551
1552
    // Compute the quotient and remainder
1553
2.23k
    const auto [quotient_1024, remainder_1024] = (sum_of_products_final + add_right_final_sum).divmod(modulus);
1554
1555
    // If we are establishing an identity and the remainder has to be zero, we need to check, that it actually is
1556
1557
2.23k
    if (fix_remainder_to_zero) {
1558
        // This is not the only check. Circuit check is coming later :)
1559
1.91k
        ASSERT(remainder_1024.lo == uint512_t(0));
1560
1.91k
    }
1561
2.23k
    const uint512_t quotient_value = quotient_1024.lo;
1562
2.23k
    const uint512_t remainder_value = remainder_1024.lo;
1563
1564
2.23k
    bigfield remainder;
1565
2.23k
    bigfield quotient;
1566
    // Constrain quotient to mitigate CRT overflow attacks
1567
2.23k
    quotient = create_from_u512_as_witness(ctx, quotient_value, false, num_quotient_bits);
1568
1569
2.23k
    if (fix_remainder_to_zero) {
1570
1.91k
        remainder = zero();
1571
        // remainder needs to be defined as wire value and not selector values to satisfy
1572
        // Ultra's bigfield custom gates
1573
1.91k
        remainder.convert_constant_to_fixed_witness(ctx);
1574
1.91k
    } else {
1575
320
        remainder = create_from_u512_as_witness(ctx, remainder_value);
1576
320
    }
1577
1578
2.23k
    unsafe_evaluate_multiple_multiply_add(new_input_left, new_input_right, new_to_add, quotient, { remainder });
1579
1580
2.23k
    remainder.set_origin_tag(new_tag);
1581
2.23k
    return remainder;
1582
2.23k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE9mult_maddERKSt6vectorIS9_SaIS9_EESE_SE_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE9mult_maddERKSt6vectorIS9_SaIS9_EESE_SE_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE9mult_maddERKSt6vectorIS6_SaIS6_EESB_SB_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE9mult_maddERKSt6vectorIS6_SaIS6_EESB_SB_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE9mult_maddERKSt6vectorIS8_SaIS8_EESD_SD_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E9mult_maddERKSt6vectorIS7_SaIS7_EESC_SC_b
1583
1584
/**
1585
 * Compute (left_a * right_a) + (left_b * right_b) + ...to_add = c mod p
1586
 *
1587
 * This is cheaper than two multiplication operations, as the above only requires one quotient/remainder
1588
 **/
1589
template <typename Builder, typename T>
1590
bigfield<Builder, T> bigfield<Builder, T>::dual_madd(const bigfield& left_a,
1591
                                                     const bigfield& right_a,
1592
                                                     const bigfield& left_b,
1593
                                                     const bigfield& right_b,
1594
                                                     const std::vector<bigfield>& to_add)
1595
1
{
1596
1
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1597
0
    left_a.reduction_check();
1598
0
    right_a.reduction_check();
1599
0
    left_b.reduction_check();
1600
0
    right_b.reduction_check();
1601
1602
0
    std::vector<bigfield> mul_left = { left_a, left_b };
1603
0
    std::vector<bigfield> mul_right = { right_a, right_b };
1604
1605
0
    return mult_madd(mul_left, mul_right, to_add);
1606
1
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE9dual_maddERKS6_S8_S8_S8_RKSt6vectorIS6_SaIS6_EE
Line
Count
Source
1595
1
{
1596
1
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
1597
1
    left_a.reduction_check();
1598
1
    right_a.reduction_check();
1599
1
    left_b.reduction_check();
1600
1
    right_b.reduction_check();
1601
1602
1
    std::vector<bigfield> mul_left = { left_a, left_b };
1603
1
    std::vector<bigfield> mul_right = { right_a, right_b };
1604
1605
1
    return mult_madd(mul_left, mul_right, to_add);
1606
1
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE9dual_maddERKS6_S8_S8_S8_RKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE9dual_maddERKS8_SA_SA_SA_RKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE9dual_maddERKS9_SB_SB_SB_RKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE9dual_maddERKS9_SB_SB_SB_RKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE9dual_maddERKS9_SB_SB_SB_RKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE9dual_maddERKS9_SB_SB_SB_RKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE9dual_maddERKS6_S8_S8_S8_RKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE9dual_maddERKS6_S8_S8_S8_RKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE9dual_maddERKS8_SA_SA_SA_RKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E9dual_maddERKS7_S9_S9_S9_RKSt6vectorIS7_SaIS7_EE
1607
1608
/**
1609
 * multiply, subtract, divide.
1610
 * This method computes:
1611
 *
1612
 * result = -(\sum{mul_left[i] * mul_right[i]} + ...to_add) / divisor
1613
 *
1614
 * Algorithm is constructed in this way to ensure that all computed terms are positive
1615
 *
1616
 * i.e. we evaluate:
1617
 * result * divisor + (\sum{mul_left[i] * mul_right[i]) + ...to_add) = 0
1618
 *
1619
 * It is critical that ALL the terms on the LHS are positive to eliminate the possiblity of underflows
1620
 * when calling `evaluate_multiple_multiply_add`
1621
 *
1622
 * only requires one quotient and remainder + overflow limbs
1623
 *
1624
 * We proxy this to mult_madd, so it only requires one quotient and remainder + overflow limbs
1625
 **/
1626
template <typename Builder, typename T>
1627
bigfield<Builder, T> bigfield<Builder, T>::msub_div(const std::vector<bigfield>& mul_left,
1628
                                                    const std::vector<bigfield>& mul_right,
1629
                                                    const bigfield& divisor,
1630
                                                    const std::vector<bigfield>& to_sub,
1631
                                                    bool enable_divisor_nz_check)
1632
340k
{
1633
    // Check the basics
1634
340k
    ASSERT(mul_left.size() == mul_right.size());
1635
340k
    ASSERT(divisor.get_value() != 0);
1636
1637
0
    OriginTag new_tag = divisor.get_origin_tag();
1638
405k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1639
405k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1640
405k
    }
1641
623k
    for (auto& element : to_sub) {
1642
623k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1643
623k
    }
1644
    // Gett he context
1645
0
    Builder* ctx = divisor.context;
1646
340k
    if (ctx == NULL) {
1647
1
        for (auto& el : mul_left) {
1648
1
            if (el.context != NULL) {
1649
1
                ctx = el.context;
1650
1
                break;
1651
1
            }
1652
1
        }
1653
1
    }
1654
340k
    if (ctx == NULL) {
1655
0
        for (auto& el : mul_right) {
1656
0
            if (el.context != NULL) {
1657
0
                ctx = el.context;
1658
0
                break;
1659
0
            }
1660
0
        }
1661
0
    }
1662
340k
    if (ctx == NULL) {
1663
0
        for (auto& el : to_sub) {
1664
0
            if (el.context != NULL) {
1665
0
                ctx = el.context;
1666
0
                break;
1667
0
            }
1668
0
        }
1669
0
    }
1670
0
    const size_t num_multiplications = mul_left.size();
1671
0
    native product_native = 0;
1672
0
    bool products_constant = true;
1673
1674
    // This check is optional, because it is heavy and often we don't need it at all
1675
340k
    if (enable_divisor_nz_check) {
1676
1
        divisor.assert_is_not_equal(zero());
1677
1
    }
1678
1679
    // Compute the sum of products
1680
745k
    for (size_t i = 0; i < num_multiplications; ++i) {
1681
405k
        const native mul_left_native(uint512_t(mul_left[i].get_value() % modulus_u512).lo);
1682
405k
        const native mul_right_native(uint512_t(mul_right[i].get_value() % modulus_u512).lo);
1683
405k
        product_native += (mul_left_native * -mul_right_native);
1684
405k
        products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant();
1685
405k
    }
1686
1687
    // Compute the sum of to_sub
1688
0
    native sub_native(0);
1689
0
    bool sub_constant = true;
1690
623k
    for (const auto& sub : to_sub) {
1691
623k
        sub_native += (uint512_t(sub.get_value() % modulus_u512).lo);
1692
623k
        sub_constant = sub_constant && sub.is_constant();
1693
623k
    }
1694
1695
0
    native divisor_native(uint512_t(divisor.get_value() % modulus_u512).lo);
1696
1697
    // Compute the result
1698
0
    const native result_native = (product_native - sub_native) / divisor_native;
1699
1700
0
    const uint1024_t result_value = uint1024_t(uint512_t(static_cast<uint256_t>(result_native)));
1701
1702
    // If everything is constant, then we just return the constant
1703
340k
    if (sub_constant && products_constant && divisor.is_constant()) {
1704
0
        auto result = bigfield(ctx, uint256_t(result_value.lo.lo));
1705
0
        result.set_origin_tag(new_tag);
1706
0
        return result;
1707
0
    }
1708
1709
340k
    ASSERT(ctx != NULL);
1710
    // Create the result witness
1711
0
    bigfield result = create_from_u512_as_witness(ctx, result_value.lo);
1712
1713
0
    std::vector<bigfield> eval_left{ result };
1714
0
    std::vector<bigfield> eval_right{ divisor };
1715
405k
    for (const auto& in : mul_left) {
1716
405k
        eval_left.emplace_back(in);
1717
405k
    }
1718
405k
    for (const auto& in : mul_right) {
1719
405k
        eval_right.emplace_back(in);
1720
405k
    }
1721
1722
0
    mult_madd(eval_left, eval_right, to_sub, true);
1723
1724
0
    result.set_origin_tag(new_tag);
1725
0
    return result;
1726
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE8msub_divERKSt6vectorIS6_SaIS6_EESB_RKS6_SB_b
Line
Count
Source
1632
313k
{
1633
    // Check the basics
1634
313k
    ASSERT(mul_left.size() == mul_right.size());
1635
313k
    ASSERT(divisor.get_value() != 0);
1636
1637
313k
    OriginTag new_tag = divisor.get_origin_tag();
1638
367k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1639
367k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1640
367k
    }
1641
590k
    for (auto& element : to_sub) {
1642
590k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1643
590k
    }
1644
    // Gett he context
1645
313k
    Builder* ctx = divisor.context;
1646
313k
    if (ctx == NULL) {
1647
1
        for (auto& el : mul_left) {
1648
1
            if (el.context != NULL) {
1649
1
                ctx = el.context;
1650
1
                break;
1651
1
            }
1652
1
        }
1653
1
    }
1654
313k
    if (ctx == NULL) {
1655
0
        for (auto& el : mul_right) {
1656
0
            if (el.context != NULL) {
1657
0
                ctx = el.context;
1658
0
                break;
1659
0
            }
1660
0
        }
1661
0
    }
1662
313k
    if (ctx == NULL) {
1663
0
        for (auto& el : to_sub) {
1664
0
            if (el.context != NULL) {
1665
0
                ctx = el.context;
1666
0
                break;
1667
0
            }
1668
0
        }
1669
0
    }
1670
313k
    const size_t num_multiplications = mul_left.size();
1671
313k
    native product_native = 0;
1672
313k
    bool products_constant = true;
1673
1674
    // This check is optional, because it is heavy and often we don't need it at all
1675
313k
    if (enable_divisor_nz_check) {
1676
1
        divisor.assert_is_not_equal(zero());
1677
1
    }
1678
1679
    // Compute the sum of products
1680
681k
    for (size_t i = 0; i < num_multiplications; ++i) {
1681
367k
        const native mul_left_native(uint512_t(mul_left[i].get_value() % modulus_u512).lo);
1682
367k
        const native mul_right_native(uint512_t(mul_right[i].get_value() % modulus_u512).lo);
1683
367k
        product_native += (mul_left_native * -mul_right_native);
1684
367k
        products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant();
1685
367k
    }
1686
1687
    // Compute the sum of to_sub
1688
313k
    native sub_native(0);
1689
313k
    bool sub_constant = true;
1690
590k
    for (const auto& sub : to_sub) {
1691
590k
        sub_native += (uint512_t(sub.get_value() % modulus_u512).lo);
1692
590k
        sub_constant = sub_constant && sub.is_constant();
1693
590k
    }
1694
1695
313k
    native divisor_native(uint512_t(divisor.get_value() % modulus_u512).lo);
1696
1697
    // Compute the result
1698
313k
    const native result_native = (product_native - sub_native) / divisor_native;
1699
1700
313k
    const uint1024_t result_value = uint1024_t(uint512_t(static_cast<uint256_t>(result_native)));
1701
1702
    // If everything is constant, then we just return the constant
1703
313k
    if (sub_constant && products_constant && divisor.is_constant()) {
1704
0
        auto result = bigfield(ctx, uint256_t(result_value.lo.lo));
1705
0
        result.set_origin_tag(new_tag);
1706
0
        return result;
1707
0
    }
1708
1709
313k
    ASSERT(ctx != NULL);
1710
    // Create the result witness
1711
313k
    bigfield result = create_from_u512_as_witness(ctx, result_value.lo);
1712
1713
313k
    std::vector<bigfield> eval_left{ result };
1714
313k
    std::vector<bigfield> eval_right{ divisor };
1715
367k
    for (const auto& in : mul_left) {
1716
367k
        eval_left.emplace_back(in);
1717
367k
    }
1718
367k
    for (const auto& in : mul_right) {
1719
367k
        eval_right.emplace_back(in);
1720
367k
    }
1721
1722
313k
    mult_madd(eval_left, eval_right, to_sub, true);
1723
1724
313k
    result.set_origin_tag(new_tag);
1725
313k
    return result;
1726
313k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE8msub_divERKSt6vectorIS6_SaIS6_EESB_RKS6_SB_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE8msub_divERKSt6vectorIS8_SaIS8_EESD_RKS8_SD_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b
Line
Count
Source
1632
1.09k
{
1633
    // Check the basics
1634
1.09k
    ASSERT(mul_left.size() == mul_right.size());
1635
1.09k
    ASSERT(divisor.get_value() != 0);
1636
1637
1.09k
    OriginTag new_tag = divisor.get_origin_tag();
1638
1.47k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1639
1.47k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1640
1.47k
    }
1641
1.17k
    for (auto& element : to_sub) {
1642
1.17k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1643
1.17k
    }
1644
    // Gett he context
1645
1.09k
    Builder* ctx = divisor.context;
1646
1.09k
    if (ctx == NULL) {
1647
0
        for (auto& el : mul_left) {
1648
0
            if (el.context != NULL) {
1649
0
                ctx = el.context;
1650
0
                break;
1651
0
            }
1652
0
        }
1653
0
    }
1654
1.09k
    if (ctx == NULL) {
1655
0
        for (auto& el : mul_right) {
1656
0
            if (el.context != NULL) {
1657
0
                ctx = el.context;
1658
0
                break;
1659
0
            }
1660
0
        }
1661
0
    }
1662
1.09k
    if (ctx == NULL) {
1663
0
        for (auto& el : to_sub) {
1664
0
            if (el.context != NULL) {
1665
0
                ctx = el.context;
1666
0
                break;
1667
0
            }
1668
0
        }
1669
0
    }
1670
1.09k
    const size_t num_multiplications = mul_left.size();
1671
1.09k
    native product_native = 0;
1672
1.09k
    bool products_constant = true;
1673
1674
    // This check is optional, because it is heavy and often we don't need it at all
1675
1.09k
    if (enable_divisor_nz_check) {
1676
0
        divisor.assert_is_not_equal(zero());
1677
0
    }
1678
1679
    // Compute the sum of products
1680
2.56k
    for (size_t i = 0; i < num_multiplications; ++i) {
1681
1.47k
        const native mul_left_native(uint512_t(mul_left[i].get_value() % modulus_u512).lo);
1682
1.47k
        const native mul_right_native(uint512_t(mul_right[i].get_value() % modulus_u512).lo);
1683
1.47k
        product_native += (mul_left_native * -mul_right_native);
1684
1.47k
        products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant();
1685
1.47k
    }
1686
1687
    // Compute the sum of to_sub
1688
1.09k
    native sub_native(0);
1689
1.09k
    bool sub_constant = true;
1690
1.17k
    for (const auto& sub : to_sub) {
1691
1.17k
        sub_native += (uint512_t(sub.get_value() % modulus_u512).lo);
1692
1.17k
        sub_constant = sub_constant && sub.is_constant();
1693
1.17k
    }
1694
1695
1.09k
    native divisor_native(uint512_t(divisor.get_value() % modulus_u512).lo);
1696
1697
    // Compute the result
1698
1.09k
    const native result_native = (product_native - sub_native) / divisor_native;
1699
1700
1.09k
    const uint1024_t result_value = uint1024_t(uint512_t(static_cast<uint256_t>(result_native)));
1701
1702
    // If everything is constant, then we just return the constant
1703
1.09k
    if (sub_constant && products_constant && divisor.is_constant()) {
1704
0
        auto result = bigfield(ctx, uint256_t(result_value.lo.lo));
1705
0
        result.set_origin_tag(new_tag);
1706
0
        return result;
1707
0
    }
1708
1709
1.09k
    ASSERT(ctx != NULL);
1710
    // Create the result witness
1711
1.09k
    bigfield result = create_from_u512_as_witness(ctx, result_value.lo);
1712
1713
1.09k
    std::vector<bigfield> eval_left{ result };
1714
1.09k
    std::vector<bigfield> eval_right{ divisor };
1715
1.47k
    for (const auto& in : mul_left) {
1716
1.47k
        eval_left.emplace_back(in);
1717
1.47k
    }
1718
1.47k
    for (const auto& in : mul_right) {
1719
1.47k
        eval_right.emplace_back(in);
1720
1.47k
    }
1721
1722
1.09k
    mult_madd(eval_left, eval_right, to_sub, true);
1723
1724
1.09k
    result.set_origin_tag(new_tag);
1725
1.09k
    return result;
1726
1.09k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE8msub_divERKSt6vectorIS9_SaIS9_EESE_RKS9_SE_b
Line
Count
Source
1632
23.4k
{
1633
    // Check the basics
1634
23.4k
    ASSERT(mul_left.size() == mul_right.size());
1635
23.4k
    ASSERT(divisor.get_value() != 0);
1636
1637
23.4k
    OriginTag new_tag = divisor.get_origin_tag();
1638
32.6k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1639
32.6k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1640
32.6k
    }
1641
28.2k
    for (auto& element : to_sub) {
1642
28.2k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1643
28.2k
    }
1644
    // Gett he context
1645
23.4k
    Builder* ctx = divisor.context;
1646
23.4k
    if (ctx == NULL) {
1647
0
        for (auto& el : mul_left) {
1648
0
            if (el.context != NULL) {
1649
0
                ctx = el.context;
1650
0
                break;
1651
0
            }
1652
0
        }
1653
0
    }
1654
23.4k
    if (ctx == NULL) {
1655
0
        for (auto& el : mul_right) {
1656
0
            if (el.context != NULL) {
1657
0
                ctx = el.context;
1658
0
                break;
1659
0
            }
1660
0
        }
1661
0
    }
1662
23.4k
    if (ctx == NULL) {
1663
0
        for (auto& el : to_sub) {
1664
0
            if (el.context != NULL) {
1665
0
                ctx = el.context;
1666
0
                break;
1667
0
            }
1668
0
        }
1669
0
    }
1670
23.4k
    const size_t num_multiplications = mul_left.size();
1671
23.4k
    native product_native = 0;
1672
23.4k
    bool products_constant = true;
1673
1674
    // This check is optional, because it is heavy and often we don't need it at all
1675
23.4k
    if (enable_divisor_nz_check) {
1676
0
        divisor.assert_is_not_equal(zero());
1677
0
    }
1678
1679
    // Compute the sum of products
1680
56.1k
    for (size_t i = 0; i < num_multiplications; ++i) {
1681
32.6k
        const native mul_left_native(uint512_t(mul_left[i].get_value() % modulus_u512).lo);
1682
32.6k
        const native mul_right_native(uint512_t(mul_right[i].get_value() % modulus_u512).lo);
1683
32.6k
        product_native += (mul_left_native * -mul_right_native);
1684
32.6k
        products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant();
1685
32.6k
    }
1686
1687
    // Compute the sum of to_sub
1688
23.4k
    native sub_native(0);
1689
23.4k
    bool sub_constant = true;
1690
28.2k
    for (const auto& sub : to_sub) {
1691
28.2k
        sub_native += (uint512_t(sub.get_value() % modulus_u512).lo);
1692
28.2k
        sub_constant = sub_constant && sub.is_constant();
1693
28.2k
    }
1694
1695
23.4k
    native divisor_native(uint512_t(divisor.get_value() % modulus_u512).lo);
1696
1697
    // Compute the result
1698
23.4k
    const native result_native = (product_native - sub_native) / divisor_native;
1699
1700
23.4k
    const uint1024_t result_value = uint1024_t(uint512_t(static_cast<uint256_t>(result_native)));
1701
1702
    // If everything is constant, then we just return the constant
1703
23.4k
    if (sub_constant && products_constant && divisor.is_constant()) {
1704
0
        auto result = bigfield(ctx, uint256_t(result_value.lo.lo));
1705
0
        result.set_origin_tag(new_tag);
1706
0
        return result;
1707
0
    }
1708
1709
23.4k
    ASSERT(ctx != NULL);
1710
    // Create the result witness
1711
23.4k
    bigfield result = create_from_u512_as_witness(ctx, result_value.lo);
1712
1713
23.4k
    std::vector<bigfield> eval_left{ result };
1714
23.4k
    std::vector<bigfield> eval_right{ divisor };
1715
32.6k
    for (const auto& in : mul_left) {
1716
32.6k
        eval_left.emplace_back(in);
1717
32.6k
    }
1718
32.6k
    for (const auto& in : mul_right) {
1719
32.6k
        eval_right.emplace_back(in);
1720
32.6k
    }
1721
1722
23.4k
    mult_madd(eval_left, eval_right, to_sub, true);
1723
1724
23.4k
    result.set_origin_tag(new_tag);
1725
23.4k
    return result;
1726
23.4k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE8msub_divERKSt6vectorIS9_SaIS9_EESE_RKS9_SE_b
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b
Line
Count
Source
1632
1.91k
{
1633
    // Check the basics
1634
1.91k
    ASSERT(mul_left.size() == mul_right.size());
1635
1.91k
    ASSERT(divisor.get_value() != 0);
1636
1637
1.91k
    OriginTag new_tag = divisor.get_origin_tag();
1638
3.81k
    for (auto [left_element, right_element] : zip_view(mul_left, mul_right)) {
1639
3.81k
        new_tag = OriginTag(new_tag, OriginTag(left_element.get_origin_tag(), right_element.get_origin_tag()));
1640
3.81k
    }
1641
2.86k
    for (auto& element : to_sub) {
1642
2.86k
        new_tag = OriginTag(new_tag, element.get_origin_tag());
1643
2.86k
    }
1644
    // Gett he context
1645
1.91k
    Builder* ctx = divisor.context;
1646
1.91k
    if (ctx == NULL) {
1647
0
        for (auto& el : mul_left) {
1648
0
            if (el.context != NULL) {
1649
0
                ctx = el.context;
1650
0
                break;
1651
0
            }
1652
0
        }
1653
0
    }
1654
1.91k
    if (ctx == NULL) {
1655
0
        for (auto& el : mul_right) {
1656
0
            if (el.context != NULL) {
1657
0
                ctx = el.context;
1658
0
                break;
1659
0
            }
1660
0
        }
1661
0
    }
1662
1.91k
    if (ctx == NULL) {
1663
0
        for (auto& el : to_sub) {
1664
0
            if (el.context != NULL) {
1665
0
                ctx = el.context;
1666
0
                break;
1667
0
            }
1668
0
        }
1669
0
    }
1670
1.91k
    const size_t num_multiplications = mul_left.size();
1671
1.91k
    native product_native = 0;
1672
1.91k
    bool products_constant = true;
1673
1674
    // This check is optional, because it is heavy and often we don't need it at all
1675
1.91k
    if (enable_divisor_nz_check) {
1676
0
        divisor.assert_is_not_equal(zero());
1677
0
    }
1678
1679
    // Compute the sum of products
1680
5.72k
    for (size_t i = 0; i < num_multiplications; ++i) {
1681
3.81k
        const native mul_left_native(uint512_t(mul_left[i].get_value() % modulus_u512).lo);
1682
3.81k
        const native mul_right_native(uint512_t(mul_right[i].get_value() % modulus_u512).lo);
1683
3.81k
        product_native += (mul_left_native * -mul_right_native);
1684
3.81k
        products_constant = products_constant && mul_left[i].is_constant() && mul_right[i].is_constant();
1685
3.81k
    }
1686
1687
    // Compute the sum of to_sub
1688
1.91k
    native sub_native(0);
1689
1.91k
    bool sub_constant = true;
1690
2.86k
    for (const auto& sub : to_sub) {
1691
2.86k
        sub_native += (uint512_t(sub.get_value() % modulus_u512).lo);
1692
2.86k
        sub_constant = sub_constant && sub.is_constant();
1693
2.86k
    }
1694
1695
1.91k
    native divisor_native(uint512_t(divisor.get_value() % modulus_u512).lo);
1696
1697
    // Compute the result
1698
1.91k
    const native result_native = (product_native - sub_native) / divisor_native;
1699
1700
1.91k
    const uint1024_t result_value = uint1024_t(uint512_t(static_cast<uint256_t>(result_native)));
1701
1702
    // If everything is constant, then we just return the constant
1703
1.91k
    if (sub_constant && products_constant && divisor.is_constant()) {
1704
0
        auto result = bigfield(ctx, uint256_t(result_value.lo.lo));
1705
0
        result.set_origin_tag(new_tag);
1706
0
        return result;
1707
0
    }
1708
1709
1.91k
    ASSERT(ctx != NULL);
1710
    // Create the result witness
1711
1.91k
    bigfield result = create_from_u512_as_witness(ctx, result_value.lo);
1712
1713
1.91k
    std::vector<bigfield> eval_left{ result };
1714
1.91k
    std::vector<bigfield> eval_right{ divisor };
1715
3.81k
    for (const auto& in : mul_left) {
1716
3.81k
        eval_left.emplace_back(in);
1717
3.81k
    }
1718
3.81k
    for (const auto& in : mul_right) {
1719
3.81k
        eval_right.emplace_back(in);
1720
3.81k
    }
1721
1722
1.91k
    mult_madd(eval_left, eval_right, to_sub, true);
1723
1724
1.91k
    result.set_origin_tag(new_tag);
1725
1.91k
    return result;
1726
1.91k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE8msub_divERKSt6vectorIS9_SaIS9_EESE_RKS9_SE_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE8msub_divERKSt6vectorIS9_SaIS9_EESE_RKS9_SE_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE8msub_divERKSt6vectorIS6_SaIS6_EESB_RKS6_SB_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE8msub_divERKSt6vectorIS6_SaIS6_EESB_RKS6_SB_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE8msub_divERKSt6vectorIS8_SaIS8_EESD_RKS8_SD_b
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E8msub_divERKSt6vectorIS7_SaIS7_EESC_RKS7_SC_b
1727
1728
template <typename Builder, typename T>
1729
bigfield<Builder, T> bigfield<Builder, T>::conditional_negate(const bool_t<Builder>& predicate) const
1730
33.7k
{
1731
33.7k
    Builder* ctx = context ? context : predicate.context;
1732
1733
33.7k
    if (is_constant() && predicate.is_constant()) {
1734
0
        auto result = *this;
1735
0
        if (predicate.get_value()) {
1736
0
            ASSERT(get_value() < modulus_u512);
1737
0
            uint512_t out_val = (modulus_u512 - get_value()) % modulus_u512;
1738
0
            result = bigfield(ctx, out_val.lo);
1739
0
        }
1740
0
        result.set_origin_tag(OriginTag(get_origin_tag(), predicate.get_origin_tag()));
1741
0
        return result;
1742
0
    }
1743
33.7k
    reduction_check();
1744
1745
33.7k
    uint256_t limb_0_maximum_value = binary_basis_limbs[0].maximum_value;
1746
33.7k
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1747
33.7k
    uint256_t limb_1_maximum_value =
1748
33.7k
        binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
1749
33.7k
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1750
33.7k
    uint256_t limb_2_maximum_value =
1751
33.7k
        binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
1752
33.7k
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1753
1754
33.7k
    uint256_t limb_3_maximum_value =
1755
33.7k
        binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
1756
1757
    // uint256_t comparison_maximum = uint256_t(modulus_u512.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4));
1758
    // uint256_t additive_term = comparison_maximum;
1759
    // TODO: This is terribly inefficient. We should change it.
1760
33.7k
    uint512_t constant_to_add = modulus_u512;
1761
87.9k
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
1762
54.2k
        constant_to_add += modulus_u512;
1763
54.2k
    }
1764
1765
33.7k
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
1766
33.7k
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
1767
33.7k
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
1768
33.7k
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
1769
1770
33.7k
    uint256_t to_add_0_u256 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS));
1771
33.7k
    uint256_t to_add_1_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2));
1772
33.7k
    uint256_t to_add_2_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3));
1773
33.7k
    uint256_t to_add_3_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4));
1774
1775
33.7k
    bb::fr to_add_0(t0 + to_add_0_u256);
1776
33.7k
    bb::fr to_add_1(t1 + to_add_1_u256);
1777
33.7k
    bb::fr to_add_2(t2 + to_add_2_u256);
1778
33.7k
    bb::fr to_add_3(to_add_3_u256 - t3);
1779
1780
    // we either return current value if predicate is false, or (limb_i - value) if predicate is true
1781
    // (1 - predicate) * value + predicate * (limb_i - value)
1782
    // = predicate * (limb_i - 2 * value) + value
1783
33.7k
    bb::fr two(2);
1784
1785
33.7k
    field_t limb_0 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[0].element * two) + to_add_0,
1786
33.7k
                                                                   binary_basis_limbs[0].element);
1787
33.7k
    field_t limb_1 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[1].element * two) + to_add_1,
1788
33.7k
                                                                   binary_basis_limbs[1].element);
1789
33.7k
    field_t limb_2 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[2].element * two) + to_add_2,
1790
33.7k
                                                                   binary_basis_limbs[2].element);
1791
33.7k
    field_t limb_3 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[3].element * two) + to_add_3,
1792
33.7k
                                                                   binary_basis_limbs[3].element);
1793
1794
33.7k
    uint256_t maximum_negated_limb_0 = to_add_0_u256 + t0;
1795
33.7k
    uint256_t maximum_negated_limb_1 = to_add_1_u256 + t1;
1796
33.7k
    uint256_t maximum_negated_limb_2 = to_add_2_u256 + t2;
1797
33.7k
    uint256_t maximum_negated_limb_3 = to_add_3_u256;
1798
1799
33.7k
    uint256_t max_limb_0 = binary_basis_limbs[0].maximum_value > maximum_negated_limb_0
1800
33.7k
                               ? binary_basis_limbs[0].maximum_value
1801
33.7k
                               : maximum_negated_limb_0;
1802
33.7k
    uint256_t max_limb_1 = binary_basis_limbs[1].maximum_value > maximum_negated_limb_1
1803
33.7k
                               ? binary_basis_limbs[1].maximum_value
1804
33.7k
                               : maximum_negated_limb_1;
1805
33.7k
    uint256_t max_limb_2 = binary_basis_limbs[2].maximum_value > maximum_negated_limb_2
1806
33.7k
                               ? binary_basis_limbs[2].maximum_value
1807
33.7k
                               : maximum_negated_limb_2;
1808
33.7k
    uint256_t max_limb_3 = binary_basis_limbs[3].maximum_value > maximum_negated_limb_3
1809
33.7k
                               ? binary_basis_limbs[3].maximum_value
1810
33.7k
                               : maximum_negated_limb_3;
1811
1812
33.7k
    bigfield result(ctx);
1813
33.7k
    result.binary_basis_limbs[0] = Limb(limb_0, max_limb_0);
1814
33.7k
    result.binary_basis_limbs[1] = Limb(limb_1, max_limb_1);
1815
33.7k
    result.binary_basis_limbs[2] = Limb(limb_2, max_limb_2);
1816
33.7k
    result.binary_basis_limbs[3] = Limb(limb_3, max_limb_3);
1817
1818
33.7k
    uint512_t constant_to_add_mod_p = constant_to_add % prime_basis.modulus;
1819
33.7k
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
1820
33.7k
    result.prime_basis_limb =
1821
33.7k
        static_cast<field_t<Builder>>(predicate).madd(-(prime_basis_limb * two) + prime_basis_to_add, prime_basis_limb);
1822
1823
33.7k
    result.set_origin_tag(OriginTag(get_origin_tag(), predicate.tag));
1824
1825
33.7k
    return result;
1826
33.7k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE18conditional_negateERKNS0_6bool_tIS4_EE
Line
Count
Source
1730
33.1k
{
1731
33.1k
    Builder* ctx = context ? context : predicate.context;
1732
1733
33.1k
    if (is_constant() && predicate.is_constant()) {
1734
0
        auto result = *this;
1735
0
        if (predicate.get_value()) {
1736
0
            ASSERT(get_value() < modulus_u512);
1737
0
            uint512_t out_val = (modulus_u512 - get_value()) % modulus_u512;
1738
0
            result = bigfield(ctx, out_val.lo);
1739
0
        }
1740
0
        result.set_origin_tag(OriginTag(get_origin_tag(), predicate.get_origin_tag()));
1741
0
        return result;
1742
0
    }
1743
33.1k
    reduction_check();
1744
1745
33.1k
    uint256_t limb_0_maximum_value = binary_basis_limbs[0].maximum_value;
1746
33.1k
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1747
33.1k
    uint256_t limb_1_maximum_value =
1748
33.1k
        binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
1749
33.1k
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1750
33.1k
    uint256_t limb_2_maximum_value =
1751
33.1k
        binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
1752
33.1k
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1753
1754
33.1k
    uint256_t limb_3_maximum_value =
1755
33.1k
        binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
1756
1757
    // uint256_t comparison_maximum = uint256_t(modulus_u512.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4));
1758
    // uint256_t additive_term = comparison_maximum;
1759
    // TODO: This is terribly inefficient. We should change it.
1760
33.1k
    uint512_t constant_to_add = modulus_u512;
1761
86.9k
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
1762
53.7k
        constant_to_add += modulus_u512;
1763
53.7k
    }
1764
1765
33.1k
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
1766
33.1k
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
1767
33.1k
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
1768
33.1k
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
1769
1770
33.1k
    uint256_t to_add_0_u256 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS));
1771
33.1k
    uint256_t to_add_1_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2));
1772
33.1k
    uint256_t to_add_2_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3));
1773
33.1k
    uint256_t to_add_3_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4));
1774
1775
33.1k
    bb::fr to_add_0(t0 + to_add_0_u256);
1776
33.1k
    bb::fr to_add_1(t1 + to_add_1_u256);
1777
33.1k
    bb::fr to_add_2(t2 + to_add_2_u256);
1778
33.1k
    bb::fr to_add_3(to_add_3_u256 - t3);
1779
1780
    // we either return current value if predicate is false, or (limb_i - value) if predicate is true
1781
    // (1 - predicate) * value + predicate * (limb_i - value)
1782
    // = predicate * (limb_i - 2 * value) + value
1783
33.1k
    bb::fr two(2);
1784
1785
33.1k
    field_t limb_0 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[0].element * two) + to_add_0,
1786
33.1k
                                                                   binary_basis_limbs[0].element);
1787
33.1k
    field_t limb_1 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[1].element * two) + to_add_1,
1788
33.1k
                                                                   binary_basis_limbs[1].element);
1789
33.1k
    field_t limb_2 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[2].element * two) + to_add_2,
1790
33.1k
                                                                   binary_basis_limbs[2].element);
1791
33.1k
    field_t limb_3 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[3].element * two) + to_add_3,
1792
33.1k
                                                                   binary_basis_limbs[3].element);
1793
1794
33.1k
    uint256_t maximum_negated_limb_0 = to_add_0_u256 + t0;
1795
33.1k
    uint256_t maximum_negated_limb_1 = to_add_1_u256 + t1;
1796
33.1k
    uint256_t maximum_negated_limb_2 = to_add_2_u256 + t2;
1797
33.1k
    uint256_t maximum_negated_limb_3 = to_add_3_u256;
1798
1799
33.1k
    uint256_t max_limb_0 = binary_basis_limbs[0].maximum_value > maximum_negated_limb_0
1800
33.1k
                               ? binary_basis_limbs[0].maximum_value
1801
33.1k
                               : maximum_negated_limb_0;
1802
33.1k
    uint256_t max_limb_1 = binary_basis_limbs[1].maximum_value > maximum_negated_limb_1
1803
33.1k
                               ? binary_basis_limbs[1].maximum_value
1804
33.1k
                               : maximum_negated_limb_1;
1805
33.1k
    uint256_t max_limb_2 = binary_basis_limbs[2].maximum_value > maximum_negated_limb_2
1806
33.1k
                               ? binary_basis_limbs[2].maximum_value
1807
33.1k
                               : maximum_negated_limb_2;
1808
33.1k
    uint256_t max_limb_3 = binary_basis_limbs[3].maximum_value > maximum_negated_limb_3
1809
33.1k
                               ? binary_basis_limbs[3].maximum_value
1810
33.1k
                               : maximum_negated_limb_3;
1811
1812
33.1k
    bigfield result(ctx);
1813
33.1k
    result.binary_basis_limbs[0] = Limb(limb_0, max_limb_0);
1814
33.1k
    result.binary_basis_limbs[1] = Limb(limb_1, max_limb_1);
1815
33.1k
    result.binary_basis_limbs[2] = Limb(limb_2, max_limb_2);
1816
33.1k
    result.binary_basis_limbs[3] = Limb(limb_3, max_limb_3);
1817
1818
33.1k
    uint512_t constant_to_add_mod_p = constant_to_add % prime_basis.modulus;
1819
33.1k
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
1820
33.1k
    result.prime_basis_limb =
1821
33.1k
        static_cast<field_t<Builder>>(predicate).madd(-(prime_basis_limb * two) + prime_basis_to_add, prime_basis_limb);
1822
1823
33.1k
    result.set_origin_tag(OriginTag(get_origin_tag(), predicate.tag));
1824
1825
33.1k
    return result;
1826
33.1k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE18conditional_negateERKNS0_6bool_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE18conditional_negateERKNS0_6bool_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E18conditional_negateERKNS0_6bool_tIS6_EE
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE18conditional_negateERKNS0_6bool_tIS4_EE
Line
Count
Source
1730
24
{
1731
24
    Builder* ctx = context ? context : predicate.context;
1732
1733
24
    if (is_constant() && predicate.is_constant()) {
1734
0
        auto result = *this;
1735
0
        if (predicate.get_value()) {
1736
0
            ASSERT(get_value() < modulus_u512);
1737
0
            uint512_t out_val = (modulus_u512 - get_value()) % modulus_u512;
1738
0
            result = bigfield(ctx, out_val.lo);
1739
0
        }
1740
0
        result.set_origin_tag(OriginTag(get_origin_tag(), predicate.get_origin_tag()));
1741
0
        return result;
1742
0
    }
1743
24
    reduction_check();
1744
1745
24
    uint256_t limb_0_maximum_value = binary_basis_limbs[0].maximum_value;
1746
24
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1747
24
    uint256_t limb_1_maximum_value =
1748
24
        binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
1749
24
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1750
24
    uint256_t limb_2_maximum_value =
1751
24
        binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
1752
24
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1753
1754
24
    uint256_t limb_3_maximum_value =
1755
24
        binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
1756
1757
    // uint256_t comparison_maximum = uint256_t(modulus_u512.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4));
1758
    // uint256_t additive_term = comparison_maximum;
1759
    // TODO: This is terribly inefficient. We should change it.
1760
24
    uint512_t constant_to_add = modulus_u512;
1761
42
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
1762
18
        constant_to_add += modulus_u512;
1763
18
    }
1764
1765
24
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
1766
24
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
1767
24
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
1768
24
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
1769
1770
24
    uint256_t to_add_0_u256 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS));
1771
24
    uint256_t to_add_1_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2));
1772
24
    uint256_t to_add_2_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3));
1773
24
    uint256_t to_add_3_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4));
1774
1775
24
    bb::fr to_add_0(t0 + to_add_0_u256);
1776
24
    bb::fr to_add_1(t1 + to_add_1_u256);
1777
24
    bb::fr to_add_2(t2 + to_add_2_u256);
1778
24
    bb::fr to_add_3(to_add_3_u256 - t3);
1779
1780
    // we either return current value if predicate is false, or (limb_i - value) if predicate is true
1781
    // (1 - predicate) * value + predicate * (limb_i - value)
1782
    // = predicate * (limb_i - 2 * value) + value
1783
24
    bb::fr two(2);
1784
1785
24
    field_t limb_0 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[0].element * two) + to_add_0,
1786
24
                                                                   binary_basis_limbs[0].element);
1787
24
    field_t limb_1 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[1].element * two) + to_add_1,
1788
24
                                                                   binary_basis_limbs[1].element);
1789
24
    field_t limb_2 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[2].element * two) + to_add_2,
1790
24
                                                                   binary_basis_limbs[2].element);
1791
24
    field_t limb_3 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[3].element * two) + to_add_3,
1792
24
                                                                   binary_basis_limbs[3].element);
1793
1794
24
    uint256_t maximum_negated_limb_0 = to_add_0_u256 + t0;
1795
24
    uint256_t maximum_negated_limb_1 = to_add_1_u256 + t1;
1796
24
    uint256_t maximum_negated_limb_2 = to_add_2_u256 + t2;
1797
24
    uint256_t maximum_negated_limb_3 = to_add_3_u256;
1798
1799
24
    uint256_t max_limb_0 = binary_basis_limbs[0].maximum_value > maximum_negated_limb_0
1800
24
                               ? binary_basis_limbs[0].maximum_value
1801
24
                               : maximum_negated_limb_0;
1802
24
    uint256_t max_limb_1 = binary_basis_limbs[1].maximum_value > maximum_negated_limb_1
1803
24
                               ? binary_basis_limbs[1].maximum_value
1804
24
                               : maximum_negated_limb_1;
1805
24
    uint256_t max_limb_2 = binary_basis_limbs[2].maximum_value > maximum_negated_limb_2
1806
24
                               ? binary_basis_limbs[2].maximum_value
1807
24
                               : maximum_negated_limb_2;
1808
24
    uint256_t max_limb_3 = binary_basis_limbs[3].maximum_value > maximum_negated_limb_3
1809
24
                               ? binary_basis_limbs[3].maximum_value
1810
24
                               : maximum_negated_limb_3;
1811
1812
24
    bigfield result(ctx);
1813
24
    result.binary_basis_limbs[0] = Limb(limb_0, max_limb_0);
1814
24
    result.binary_basis_limbs[1] = Limb(limb_1, max_limb_1);
1815
24
    result.binary_basis_limbs[2] = Limb(limb_2, max_limb_2);
1816
24
    result.binary_basis_limbs[3] = Limb(limb_3, max_limb_3);
1817
1818
24
    uint512_t constant_to_add_mod_p = constant_to_add % prime_basis.modulus;
1819
24
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
1820
24
    result.prime_basis_limb =
1821
24
        static_cast<field_t<Builder>>(predicate).madd(-(prime_basis_limb * two) + prime_basis_to_add, prime_basis_limb);
1822
1823
24
    result.set_origin_tag(OriginTag(get_origin_tag(), predicate.tag));
1824
1825
24
    return result;
1826
24
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE18conditional_negateERKNS0_6bool_tIS4_EE
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE18conditional_negateERKNS0_6bool_tIS6_EE
Line
Count
Source
1730
576
{
1731
576
    Builder* ctx = context ? context : predicate.context;
1732
1733
576
    if (is_constant() && predicate.is_constant()) {
1734
0
        auto result = *this;
1735
0
        if (predicate.get_value()) {
1736
0
            ASSERT(get_value() < modulus_u512);
1737
0
            uint512_t out_val = (modulus_u512 - get_value()) % modulus_u512;
1738
0
            result = bigfield(ctx, out_val.lo);
1739
0
        }
1740
0
        result.set_origin_tag(OriginTag(get_origin_tag(), predicate.get_origin_tag()));
1741
0
        return result;
1742
0
    }
1743
576
    reduction_check();
1744
1745
576
    uint256_t limb_0_maximum_value = binary_basis_limbs[0].maximum_value;
1746
576
    uint64_t limb_0_borrow_shift = std::max(limb_0_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1747
576
    uint256_t limb_1_maximum_value =
1748
576
        binary_basis_limbs[1].maximum_value + (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS));
1749
576
    uint64_t limb_1_borrow_shift = std::max(limb_1_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1750
576
    uint256_t limb_2_maximum_value =
1751
576
        binary_basis_limbs[2].maximum_value + (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS));
1752
576
    uint64_t limb_2_borrow_shift = std::max(limb_2_maximum_value.get_msb() + 1, NUM_LIMB_BITS);
1753
1754
576
    uint256_t limb_3_maximum_value =
1755
576
        binary_basis_limbs[3].maximum_value + (uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
1756
1757
    // uint256_t comparison_maximum = uint256_t(modulus_u512.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4));
1758
    // uint256_t additive_term = comparison_maximum;
1759
    // TODO: This is terribly inefficient. We should change it.
1760
576
    uint512_t constant_to_add = modulus_u512;
1761
1.00k
    while (constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo <= limb_3_maximum_value) {
1762
432
        constant_to_add += modulus_u512;
1763
432
    }
1764
1765
576
    uint256_t t0(uint256_t(1) << limb_0_borrow_shift);
1766
576
    uint256_t t1((uint256_t(1) << limb_1_borrow_shift) - (uint256_t(1) << (limb_0_borrow_shift - NUM_LIMB_BITS)));
1767
576
    uint256_t t2((uint256_t(1) << limb_2_borrow_shift) - (uint256_t(1) << (limb_1_borrow_shift - NUM_LIMB_BITS)));
1768
576
    uint256_t t3(uint256_t(1) << (limb_2_borrow_shift - NUM_LIMB_BITS));
1769
1770
576
    uint256_t to_add_0_u256 = uint256_t(constant_to_add.slice(0, NUM_LIMB_BITS));
1771
576
    uint256_t to_add_1_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2));
1772
576
    uint256_t to_add_2_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3));
1773
576
    uint256_t to_add_3_u256 = uint256_t(constant_to_add.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4));
1774
1775
576
    bb::fr to_add_0(t0 + to_add_0_u256);
1776
576
    bb::fr to_add_1(t1 + to_add_1_u256);
1777
576
    bb::fr to_add_2(t2 + to_add_2_u256);
1778
576
    bb::fr to_add_3(to_add_3_u256 - t3);
1779
1780
    // we either return current value if predicate is false, or (limb_i - value) if predicate is true
1781
    // (1 - predicate) * value + predicate * (limb_i - value)
1782
    // = predicate * (limb_i - 2 * value) + value
1783
576
    bb::fr two(2);
1784
1785
576
    field_t limb_0 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[0].element * two) + to_add_0,
1786
576
                                                                   binary_basis_limbs[0].element);
1787
576
    field_t limb_1 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[1].element * two) + to_add_1,
1788
576
                                                                   binary_basis_limbs[1].element);
1789
576
    field_t limb_2 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[2].element * two) + to_add_2,
1790
576
                                                                   binary_basis_limbs[2].element);
1791
576
    field_t limb_3 = static_cast<field_t<Builder>>(predicate).madd(-(binary_basis_limbs[3].element * two) + to_add_3,
1792
576
                                                                   binary_basis_limbs[3].element);
1793
1794
576
    uint256_t maximum_negated_limb_0 = to_add_0_u256 + t0;
1795
576
    uint256_t maximum_negated_limb_1 = to_add_1_u256 + t1;
1796
576
    uint256_t maximum_negated_limb_2 = to_add_2_u256 + t2;
1797
576
    uint256_t maximum_negated_limb_3 = to_add_3_u256;
1798
1799
576
    uint256_t max_limb_0 = binary_basis_limbs[0].maximum_value > maximum_negated_limb_0
1800
576
                               ? binary_basis_limbs[0].maximum_value
1801
576
                               : maximum_negated_limb_0;
1802
576
    uint256_t max_limb_1 = binary_basis_limbs[1].maximum_value > maximum_negated_limb_1
1803
576
                               ? binary_basis_limbs[1].maximum_value
1804
576
                               : maximum_negated_limb_1;
1805
576
    uint256_t max_limb_2 = binary_basis_limbs[2].maximum_value > maximum_negated_limb_2
1806
576
                               ? binary_basis_limbs[2].maximum_value
1807
576
                               : maximum_negated_limb_2;
1808
576
    uint256_t max_limb_3 = binary_basis_limbs[3].maximum_value > maximum_negated_limb_3
1809
576
                               ? binary_basis_limbs[3].maximum_value
1810
576
                               : maximum_negated_limb_3;
1811
1812
576
    bigfield result(ctx);
1813
576
    result.binary_basis_limbs[0] = Limb(limb_0, max_limb_0);
1814
576
    result.binary_basis_limbs[1] = Limb(limb_1, max_limb_1);
1815
576
    result.binary_basis_limbs[2] = Limb(limb_2, max_limb_2);
1816
576
    result.binary_basis_limbs[3] = Limb(limb_3, max_limb_3);
1817
1818
576
    uint512_t constant_to_add_mod_p = constant_to_add % prime_basis.modulus;
1819
576
    field_t prime_basis_to_add(ctx, bb::fr(constant_to_add_mod_p.lo));
1820
576
    result.prime_basis_limb =
1821
576
        static_cast<field_t<Builder>>(predicate).madd(-(prime_basis_limb * two) + prime_basis_to_add, prime_basis_limb);
1822
1823
576
    result.set_origin_tag(OriginTag(get_origin_tag(), predicate.tag));
1824
1825
576
    return result;
1826
576
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE18conditional_negateERKNS0_6bool_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE18conditional_negateERKNS0_6bool_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE18conditional_negateERKNS0_6bool_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE18conditional_negateERKNS0_6bool_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE18conditional_negateERKNS0_6bool_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE18conditional_negateERKNS0_6bool_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE18conditional_negateERKNS0_6bool_tIS4_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE18conditional_negateERKNS0_6bool_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E18conditional_negateERKNS0_6bool_tIS6_EE
1827
1828
/**
1829
 * @brief Create an element which is equal to either this or other based on the predicate
1830
 *
1831
 * @tparam Builder
1832
 * @tparam T
1833
 * @param other The other bigfield element
1834
 * @param predicate Predicate controlling the result (0 for this, 1 for the other)
1835
 * @return Resulting element
1836
 */
1837
template <typename Builder, typename T>
1838
bigfield<Builder, T> bigfield<Builder, T>::conditional_select(const bigfield& other,
1839
                                                              const bool_t<Builder>& predicate) const
1840
154k
{
1841
154k
    if (is_constant() && other.is_constant() && predicate.is_constant()) {
1842
186
        if (predicate.get_value()) {
1843
11
            return other;
1844
11
        }
1845
175
        return *this;
1846
186
    }
1847
154k
    Builder* ctx = context ? context : (other.context ? other.context : predicate.context);
1848
1849
    // TODO: use field_t::conditional_assign method
1850
154k
    field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd(
1851
154k
        other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1852
154k
    field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd(
1853
154k
        other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1854
154k
    field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd(
1855
154k
        other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1856
154k
    field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd(
1857
154k
        other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1858
154k
    field_t prime_limb =
1859
154k
        static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb);
1860
1861
154k
    bigfield result(ctx);
1862
    // the maximum of the maximal values of elements is large enough
1863
154k
    result.binary_basis_limbs[0] =
1864
154k
        Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value));
1865
154k
    result.binary_basis_limbs[1] =
1866
154k
        Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value));
1867
154k
    result.binary_basis_limbs[2] =
1868
154k
        Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value));
1869
154k
    result.binary_basis_limbs[3] =
1870
154k
        Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value));
1871
154k
    result.prime_basis_limb = prime_limb;
1872
154k
    result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag));
1873
154k
    return result;
1874
154k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE18conditional_selectERKS6_RKNS0_6bool_tIS4_EE
Line
Count
Source
1840
137k
{
1841
137k
    if (is_constant() && other.is_constant() && predicate.is_constant()) {
1842
165
        if (predicate.get_value()) {
1843
11
            return other;
1844
11
        }
1845
154
        return *this;
1846
165
    }
1847
137k
    Builder* ctx = context ? context : (other.context ? other.context : predicate.context);
1848
1849
    // TODO: use field_t::conditional_assign method
1850
137k
    field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd(
1851
137k
        other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1852
137k
    field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd(
1853
137k
        other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1854
137k
    field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd(
1855
137k
        other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1856
137k
    field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd(
1857
137k
        other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1858
137k
    field_t prime_limb =
1859
137k
        static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb);
1860
1861
137k
    bigfield result(ctx);
1862
    // the maximum of the maximal values of elements is large enough
1863
137k
    result.binary_basis_limbs[0] =
1864
137k
        Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value));
1865
137k
    result.binary_basis_limbs[1] =
1866
137k
        Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value));
1867
137k
    result.binary_basis_limbs[2] =
1868
137k
        Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value));
1869
137k
    result.binary_basis_limbs[3] =
1870
137k
        Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value));
1871
137k
    result.prime_basis_limb = prime_limb;
1872
137k
    result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag));
1873
137k
    return result;
1874
137k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE18conditional_selectERKS6_RKNS0_6bool_tIS4_EE
Line
Count
Source
1840
50
{
1841
50
    if (is_constant() && other.is_constant() && predicate.is_constant()) {
1842
0
        if (predicate.get_value()) {
1843
0
            return other;
1844
0
        }
1845
0
        return *this;
1846
0
    }
1847
50
    Builder* ctx = context ? context : (other.context ? other.context : predicate.context);
1848
1849
    // TODO: use field_t::conditional_assign method
1850
50
    field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd(
1851
50
        other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1852
50
    field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd(
1853
50
        other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1854
50
    field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd(
1855
50
        other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1856
50
    field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd(
1857
50
        other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1858
50
    field_t prime_limb =
1859
50
        static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb);
1860
1861
50
    bigfield result(ctx);
1862
    // the maximum of the maximal values of elements is large enough
1863
50
    result.binary_basis_limbs[0] =
1864
50
        Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value));
1865
50
    result.binary_basis_limbs[1] =
1866
50
        Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value));
1867
50
    result.binary_basis_limbs[2] =
1868
50
        Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value));
1869
50
    result.binary_basis_limbs[3] =
1870
50
        Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value));
1871
50
    result.prime_basis_limb = prime_limb;
1872
50
    result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag));
1873
50
    return result;
1874
50
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE18conditional_selectERKS8_RKNS0_6bool_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E18conditional_selectERKS7_RKNS0_6bool_tIS6_EE
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE18conditional_selectERKS7_RKNS0_6bool_tIS4_EE
Line
Count
Source
1840
669
{
1841
669
    if (is_constant() && other.is_constant() && predicate.is_constant()) {
1842
3
        if (predicate.get_value()) {
1843
0
            return other;
1844
0
        }
1845
3
        return *this;
1846
3
    }
1847
666
    Builder* ctx = context ? context : (other.context ? other.context : predicate.context);
1848
1849
    // TODO: use field_t::conditional_assign method
1850
666
    field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd(
1851
666
        other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1852
666
    field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd(
1853
666
        other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1854
666
    field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd(
1855
666
        other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1856
666
    field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd(
1857
666
        other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1858
666
    field_t prime_limb =
1859
666
        static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb);
1860
1861
666
    bigfield result(ctx);
1862
    // the maximum of the maximal values of elements is large enough
1863
666
    result.binary_basis_limbs[0] =
1864
666
        Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value));
1865
666
    result.binary_basis_limbs[1] =
1866
666
        Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value));
1867
666
    result.binary_basis_limbs[2] =
1868
666
        Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value));
1869
666
    result.binary_basis_limbs[3] =
1870
666
        Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value));
1871
666
    result.prime_basis_limb = prime_limb;
1872
666
    result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag));
1873
666
    return result;
1874
669
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE18conditional_selectERKS7_RKNS0_6bool_tIS4_EE
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE18conditional_selectERKS9_RKNS0_6bool_tIS6_EE
Line
Count
Source
1840
16.2k
{
1841
16.2k
    if (is_constant() && other.is_constant() && predicate.is_constant()) {
1842
0
        if (predicate.get_value()) {
1843
0
            return other;
1844
0
        }
1845
0
        return *this;
1846
0
    }
1847
16.2k
    Builder* ctx = context ? context : (other.context ? other.context : predicate.context);
1848
1849
    // TODO: use field_t::conditional_assign method
1850
16.2k
    field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd(
1851
16.2k
        other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1852
16.2k
    field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd(
1853
16.2k
        other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1854
16.2k
    field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd(
1855
16.2k
        other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1856
16.2k
    field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd(
1857
16.2k
        other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1858
16.2k
    field_t prime_limb =
1859
16.2k
        static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb);
1860
1861
16.2k
    bigfield result(ctx);
1862
    // the maximum of the maximal values of elements is large enough
1863
16.2k
    result.binary_basis_limbs[0] =
1864
16.2k
        Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value));
1865
16.2k
    result.binary_basis_limbs[1] =
1866
16.2k
        Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value));
1867
16.2k
    result.binary_basis_limbs[2] =
1868
16.2k
        Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value));
1869
16.2k
    result.binary_basis_limbs[3] =
1870
16.2k
        Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value));
1871
16.2k
    result.prime_basis_limb = prime_limb;
1872
16.2k
    result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag));
1873
16.2k
    return result;
1874
16.2k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE18conditional_selectERKS9_RKNS0_6bool_tIS6_EE
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE18conditional_selectERKS7_RKNS0_6bool_tIS4_EE
Line
Count
Source
1840
199
{
1841
199
    if (is_constant() && other.is_constant() && predicate.is_constant()) {
1842
18
        if (predicate.get_value()) {
1843
0
            return other;
1844
0
        }
1845
18
        return *this;
1846
18
    }
1847
181
    Builder* ctx = context ? context : (other.context ? other.context : predicate.context);
1848
1849
    // TODO: use field_t::conditional_assign method
1850
181
    field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd(
1851
181
        other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1852
181
    field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd(
1853
181
        other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1854
181
    field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd(
1855
181
        other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1856
181
    field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd(
1857
181
        other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1858
181
    field_t prime_limb =
1859
181
        static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb);
1860
1861
181
    bigfield result(ctx);
1862
    // the maximum of the maximal values of elements is large enough
1863
181
    result.binary_basis_limbs[0] =
1864
181
        Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value));
1865
181
    result.binary_basis_limbs[1] =
1866
181
        Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value));
1867
181
    result.binary_basis_limbs[2] =
1868
181
        Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value));
1869
181
    result.binary_basis_limbs[3] =
1870
181
        Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value));
1871
181
    result.prime_basis_limb = prime_limb;
1872
181
    result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag));
1873
181
    return result;
1874
199
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE18conditional_selectERKS7_RKNS0_6bool_tIS4_EE
Line
Count
Source
1840
10
{
1841
10
    if (is_constant() && other.is_constant() && predicate.is_constant()) {
1842
0
        if (predicate.get_value()) {
1843
0
            return other;
1844
0
        }
1845
0
        return *this;
1846
0
    }
1847
10
    Builder* ctx = context ? context : (other.context ? other.context : predicate.context);
1848
1849
    // TODO: use field_t::conditional_assign method
1850
10
    field_t binary_limb_0 = static_cast<field_t<Builder>>(predicate).madd(
1851
10
        other.binary_basis_limbs[0].element - binary_basis_limbs[0].element, binary_basis_limbs[0].element);
1852
10
    field_t binary_limb_1 = static_cast<field_t<Builder>>(predicate).madd(
1853
10
        other.binary_basis_limbs[1].element - binary_basis_limbs[1].element, binary_basis_limbs[1].element);
1854
10
    field_t binary_limb_2 = static_cast<field_t<Builder>>(predicate).madd(
1855
10
        other.binary_basis_limbs[2].element - binary_basis_limbs[2].element, binary_basis_limbs[2].element);
1856
10
    field_t binary_limb_3 = static_cast<field_t<Builder>>(predicate).madd(
1857
10
        other.binary_basis_limbs[3].element - binary_basis_limbs[3].element, binary_basis_limbs[3].element);
1858
10
    field_t prime_limb =
1859
10
        static_cast<field_t<Builder>>(predicate).madd(other.prime_basis_limb - prime_basis_limb, prime_basis_limb);
1860
1861
10
    bigfield result(ctx);
1862
    // the maximum of the maximal values of elements is large enough
1863
10
    result.binary_basis_limbs[0] =
1864
10
        Limb(binary_limb_0, std::max(binary_basis_limbs[0].maximum_value, other.binary_basis_limbs[0].maximum_value));
1865
10
    result.binary_basis_limbs[1] =
1866
10
        Limb(binary_limb_1, std::max(binary_basis_limbs[1].maximum_value, other.binary_basis_limbs[1].maximum_value));
1867
10
    result.binary_basis_limbs[2] =
1868
10
        Limb(binary_limb_2, std::max(binary_basis_limbs[2].maximum_value, other.binary_basis_limbs[2].maximum_value));
1869
10
    result.binary_basis_limbs[3] =
1870
10
        Limb(binary_limb_3, std::max(binary_basis_limbs[3].maximum_value, other.binary_basis_limbs[3].maximum_value));
1871
10
    result.prime_basis_limb = prime_limb;
1872
10
    result.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag(), predicate.tag));
1873
10
    return result;
1874
10
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE18conditional_selectERKS9_RKNS0_6bool_tIS6_EE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE18conditional_selectERKS9_RKNS0_6bool_tIS6_EE
1875
1876
/**
1877
 * @brief Validate whether two bigfield elements are equal to each other
1878
 * @details To evaluate whether `(a == b)`, we use result boolean `r` to evaluate the following logic:
1879
 *          (n.b all algebra involving bigfield elements is done in the bigfield)
1880
 *              1. If `r == 1` , `a - b == 0`
1881
 *              2. If `r == 0`, `a - b` posesses an inverse `I` i.e. `(a - b) * I - 1 == 0`
1882
 *          We efficiently evaluate this logic by evaluating a single expression `(a - b)*X = Y`
1883
 *          We use conditional assignment logic to define `X, Y` to be the following:
1884
 *              If `r == 1` then `X = 1, Y = 0`
1885
 *              If `r == 0` then `X = I, Y = 1`
1886
 *          This allows us to evaluate `operator==` using only 1 bigfield multiplication operation.
1887
 *          We can check the product equals 0 or 1 by directly evaluating the binary basis/prime basis limbs of Y.
1888
 *          i.e. if `r == 1` then `(a - b)*X` should have 0 for all limb values
1889
 *               if `r == 0` then `(a - b)*X` should have 1 in the least significant binary basis limb and 0
1890
 * elsewhere
1891
 * @tparam Builder
1892
 * @tparam T
1893
 * @param other
1894
 * @return bool_t<Builder>
1895
 */
1896
template <typename Builder, typename T> bool_t<Builder> bigfield<Builder, T>::operator==(const bigfield& other) const
1897
27.3k
{
1898
27.3k
    Builder* ctx = context ? context : other.get_context();
1899
27.3k
    auto lhs = get_value() % modulus_u512;
1900
27.3k
    auto rhs = other.get_value() % modulus_u512;
1901
27.3k
    bool is_equal_raw = (lhs == rhs);
1902
27.3k
    if (!ctx) {
1903
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/660): null context _should_ mean that both are
1904
        // constant, but we check with an assertion to be sure.
1905
0
        ASSERT(is_constant() && other.is_constant());
1906
0
        return is_equal_raw;
1907
0
    }
1908
27.3k
    bool_t<Builder> is_equal = witness_t<Builder>(ctx, is_equal_raw);
1909
1910
27.3k
    bigfield diff = (*this) - other;
1911
1912
    // TODO(https://github.com/AztecProtocol/barretenberg/issues/999): get native values efficiently (i.e. if u512
1913
    // value fits in a u256, subtract off modulus until u256 fits into finite field)
1914
27.3k
    native diff_native = native((diff.get_value() % modulus_u512).lo);
1915
27.3k
    native inverse_native = is_equal_raw ? 0 : diff_native.invert();
1916
1917
27.3k
    bigfield inverse = bigfield::from_witness(ctx, inverse_native);
1918
1919
27.3k
    bigfield multiplicand = bigfield::conditional_assign(is_equal, one(), inverse);
1920
1921
27.3k
    bigfield product = diff * multiplicand;
1922
1923
27.3k
    field_t result = field_t<Builder>::conditional_assign(is_equal, 0, 1);
1924
1925
27.3k
    product.prime_basis_limb.assert_equal(result);
1926
27.3k
    product.binary_basis_limbs[0].element.assert_equal(result);
1927
27.3k
    product.binary_basis_limbs[1].element.assert_equal(0);
1928
27.3k
    product.binary_basis_limbs[2].element.assert_equal(0);
1929
27.3k
    product.binary_basis_limbs[3].element.assert_equal(0);
1930
27.3k
    is_equal.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
1931
27.3k
    return is_equal;
1932
27.3k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEeqERKS6_
Line
Count
Source
1897
23.9k
{
1898
23.9k
    Builder* ctx = context ? context : other.get_context();
1899
23.9k
    auto lhs = get_value() % modulus_u512;
1900
23.9k
    auto rhs = other.get_value() % modulus_u512;
1901
23.9k
    bool is_equal_raw = (lhs == rhs);
1902
23.9k
    if (!ctx) {
1903
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/660): null context _should_ mean that both are
1904
        // constant, but we check with an assertion to be sure.
1905
0
        ASSERT(is_constant() && other.is_constant());
1906
0
        return is_equal_raw;
1907
0
    }
1908
23.9k
    bool_t<Builder> is_equal = witness_t<Builder>(ctx, is_equal_raw);
1909
1910
23.9k
    bigfield diff = (*this) - other;
1911
1912
    // TODO(https://github.com/AztecProtocol/barretenberg/issues/999): get native values efficiently (i.e. if u512
1913
    // value fits in a u256, subtract off modulus until u256 fits into finite field)
1914
23.9k
    native diff_native = native((diff.get_value() % modulus_u512).lo);
1915
23.9k
    native inverse_native = is_equal_raw ? 0 : diff_native.invert();
1916
1917
23.9k
    bigfield inverse = bigfield::from_witness(ctx, inverse_native);
1918
1919
23.9k
    bigfield multiplicand = bigfield::conditional_assign(is_equal, one(), inverse);
1920
1921
23.9k
    bigfield product = diff * multiplicand;
1922
1923
23.9k
    field_t result = field_t<Builder>::conditional_assign(is_equal, 0, 1);
1924
1925
23.9k
    product.prime_basis_limb.assert_equal(result);
1926
23.9k
    product.binary_basis_limbs[0].element.assert_equal(result);
1927
23.9k
    product.binary_basis_limbs[1].element.assert_equal(0);
1928
23.9k
    product.binary_basis_limbs[2].element.assert_equal(0);
1929
23.9k
    product.binary_basis_limbs[3].element.assert_equal(0);
1930
23.9k
    is_equal.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
1931
23.9k
    return is_equal;
1932
23.9k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEeqERKS6_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEeqERKS8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EeqERKS7_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEEeqERKS7_
Line
Count
Source
1897
132
{
1898
132
    Builder* ctx = context ? context : other.get_context();
1899
132
    auto lhs = get_value() % modulus_u512;
1900
132
    auto rhs = other.get_value() % modulus_u512;
1901
132
    bool is_equal_raw = (lhs == rhs);
1902
132
    if (!ctx) {
1903
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/660): null context _should_ mean that both are
1904
        // constant, but we check with an assertion to be sure.
1905
0
        ASSERT(is_constant() && other.is_constant());
1906
0
        return is_equal_raw;
1907
0
    }
1908
132
    bool_t<Builder> is_equal = witness_t<Builder>(ctx, is_equal_raw);
1909
1910
132
    bigfield diff = (*this) - other;
1911
1912
    // TODO(https://github.com/AztecProtocol/barretenberg/issues/999): get native values efficiently (i.e. if u512
1913
    // value fits in a u256, subtract off modulus until u256 fits into finite field)
1914
132
    native diff_native = native((diff.get_value() % modulus_u512).lo);
1915
132
    native inverse_native = is_equal_raw ? 0 : diff_native.invert();
1916
1917
132
    bigfield inverse = bigfield::from_witness(ctx, inverse_native);
1918
1919
132
    bigfield multiplicand = bigfield::conditional_assign(is_equal, one(), inverse);
1920
1921
132
    bigfield product = diff * multiplicand;
1922
1923
132
    field_t result = field_t<Builder>::conditional_assign(is_equal, 0, 1);
1924
1925
132
    product.prime_basis_limb.assert_equal(result);
1926
132
    product.binary_basis_limbs[0].element.assert_equal(result);
1927
132
    product.binary_basis_limbs[1].element.assert_equal(0);
1928
132
    product.binary_basis_limbs[2].element.assert_equal(0);
1929
132
    product.binary_basis_limbs[3].element.assert_equal(0);
1930
132
    is_equal.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
1931
132
    return is_equal;
1932
132
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEEeqERKS7_
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEEeqERKS9_
Line
Count
Source
1897
3.16k
{
1898
3.16k
    Builder* ctx = context ? context : other.get_context();
1899
3.16k
    auto lhs = get_value() % modulus_u512;
1900
3.16k
    auto rhs = other.get_value() % modulus_u512;
1901
3.16k
    bool is_equal_raw = (lhs == rhs);
1902
3.16k
    if (!ctx) {
1903
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/660): null context _should_ mean that both are
1904
        // constant, but we check with an assertion to be sure.
1905
0
        ASSERT(is_constant() && other.is_constant());
1906
0
        return is_equal_raw;
1907
0
    }
1908
3.16k
    bool_t<Builder> is_equal = witness_t<Builder>(ctx, is_equal_raw);
1909
1910
3.16k
    bigfield diff = (*this) - other;
1911
1912
    // TODO(https://github.com/AztecProtocol/barretenberg/issues/999): get native values efficiently (i.e. if u512
1913
    // value fits in a u256, subtract off modulus until u256 fits into finite field)
1914
3.16k
    native diff_native = native((diff.get_value() % modulus_u512).lo);
1915
3.16k
    native inverse_native = is_equal_raw ? 0 : diff_native.invert();
1916
1917
3.16k
    bigfield inverse = bigfield::from_witness(ctx, inverse_native);
1918
1919
3.16k
    bigfield multiplicand = bigfield::conditional_assign(is_equal, one(), inverse);
1920
1921
3.16k
    bigfield product = diff * multiplicand;
1922
1923
3.16k
    field_t result = field_t<Builder>::conditional_assign(is_equal, 0, 1);
1924
1925
3.16k
    product.prime_basis_limb.assert_equal(result);
1926
3.16k
    product.binary_basis_limbs[0].element.assert_equal(result);
1927
3.16k
    product.binary_basis_limbs[1].element.assert_equal(0);
1928
3.16k
    product.binary_basis_limbs[2].element.assert_equal(0);
1929
3.16k
    product.binary_basis_limbs[3].element.assert_equal(0);
1930
3.16k
    is_equal.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
1931
3.16k
    return is_equal;
1932
3.16k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEEeqERKS9_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEEeqERKS7_
Line
Count
Source
1897
30
{
1898
30
    Builder* ctx = context ? context : other.get_context();
1899
30
    auto lhs = get_value() % modulus_u512;
1900
30
    auto rhs = other.get_value() % modulus_u512;
1901
30
    bool is_equal_raw = (lhs == rhs);
1902
30
    if (!ctx) {
1903
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/660): null context _should_ mean that both are
1904
        // constant, but we check with an assertion to be sure.
1905
0
        ASSERT(is_constant() && other.is_constant());
1906
0
        return is_equal_raw;
1907
0
    }
1908
30
    bool_t<Builder> is_equal = witness_t<Builder>(ctx, is_equal_raw);
1909
1910
30
    bigfield diff = (*this) - other;
1911
1912
    // TODO(https://github.com/AztecProtocol/barretenberg/issues/999): get native values efficiently (i.e. if u512
1913
    // value fits in a u256, subtract off modulus until u256 fits into finite field)
1914
30
    native diff_native = native((diff.get_value() % modulus_u512).lo);
1915
30
    native inverse_native = is_equal_raw ? 0 : diff_native.invert();
1916
1917
30
    bigfield inverse = bigfield::from_witness(ctx, inverse_native);
1918
1919
30
    bigfield multiplicand = bigfield::conditional_assign(is_equal, one(), inverse);
1920
1921
30
    bigfield product = diff * multiplicand;
1922
1923
30
    field_t result = field_t<Builder>::conditional_assign(is_equal, 0, 1);
1924
1925
30
    product.prime_basis_limb.assert_equal(result);
1926
30
    product.binary_basis_limbs[0].element.assert_equal(result);
1927
30
    product.binary_basis_limbs[1].element.assert_equal(0);
1928
30
    product.binary_basis_limbs[2].element.assert_equal(0);
1929
30
    product.binary_basis_limbs[3].element.assert_equal(0);
1930
30
    is_equal.set_origin_tag(OriginTag(get_origin_tag(), other.get_origin_tag()));
1931
30
    return is_equal;
1932
30
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEEeqERKS7_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEEeqERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEEeqERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEEeqERKS6_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEEeqERKS6_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEEeqERKS8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_EeqERKS7_
1933
1934
/**
1935
 * REDUCTION CHECK
1936
 *
1937
 * When performing bigfield operations, we need to ensure the maximum value is less than:
1938
 *      sqrt(2^{272} * native_modulus)
1939
 *
1940
 * We also need to ensure each binary basis limb is less than the maximum limb value
1941
 *
1942
 * This prevents our field arithmetic from overflowing the native modulus boundary, whilst ensuring we can
1943
 * still use the chinese remainder theorem to validate field multiplications with a reduced number of range checks
1944
 *
1945
 **/
1946
template <typename Builder, typename T> void bigfield<Builder, T>::reduction_check() const
1947
9.68M
{
1948
1949
9.68M
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
1.15M
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
1.15M
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
1.15M
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
1.15M
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
1.15M
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
1.15M
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
1.15M
                                               prime_basis_limb.get_origin_tag() });
1959
1.15M
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
1.15M
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
1.15M
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
1.15M
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
1.15M
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
1.15M
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
1.15M
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
1.15M
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
1.15M
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
1.15M
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
1.15M
        return;
1971
1.15M
    }
1972
1973
8.52M
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
8.52M
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
8.52M
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
8.52M
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
8.52M
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
8.52M
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
8.52M
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
96
        self_reduce();
1981
96
    }
1982
8.52M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE15reduction_checkEv
Line
Count
Source
1947
8.82M
{
1948
1949
8.82M
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
1.05M
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
1.05M
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
1.05M
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
1.05M
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
1.05M
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
1.05M
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
1.05M
                                               prime_basis_limb.get_origin_tag() });
1959
1.05M
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
1.05M
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
1.05M
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
1.05M
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
1.05M
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
1.05M
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
1.05M
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
1.05M
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
1.05M
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
1.05M
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
1.05M
        return;
1971
1.05M
    }
1972
1973
7.76M
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
7.76M
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
7.76M
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
7.76M
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
7.76M
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
7.76M
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
7.76M
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
90
        self_reduce();
1981
90
    }
1982
7.76M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE15reduction_checkEv
Line
Count
Source
1947
1.46k
{
1948
1949
1.46k
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
56
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
56
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
56
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
56
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
56
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
56
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
56
                                               prime_basis_limb.get_origin_tag() });
1959
56
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
56
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
56
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
56
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
56
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
56
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
56
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
56
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
56
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
56
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
56
        return;
1971
56
    }
1972
1973
1.40k
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
1.40k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
1.40k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
1.40k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
1.40k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
1.40k
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
1.40k
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
6
        self_reduce();
1981
6
    }
1982
1.40k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE15reduction_checkEv
Line
Count
Source
1947
40
{
1948
1949
40
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
8
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
8
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
8
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
8
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
8
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
8
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
8
                                               prime_basis_limb.get_origin_tag() });
1959
8
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
8
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
8
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
8
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
8
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
8
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
8
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
8
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
8
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
8
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
8
        return;
1971
8
    }
1972
1973
32
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
32
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
32
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
32
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
32
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
32
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
32
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
0
        self_reduce();
1981
0
    }
1982
32
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E15reduction_checkEv
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE15reduction_checkEv
Line
Count
Source
1947
34.7k
{
1948
1949
34.7k
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
4.11k
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
4.11k
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
4.11k
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
4.11k
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
4.11k
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
4.11k
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
4.11k
                                               prime_basis_limb.get_origin_tag() });
1959
4.11k
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
4.11k
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
4.11k
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
4.11k
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
4.11k
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
4.11k
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
4.11k
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
4.11k
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
4.11k
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
4.11k
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
4.11k
        return;
1971
4.11k
    }
1972
1973
30.5k
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
30.5k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
30.5k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
30.5k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
30.5k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
30.5k
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
30.5k
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
0
        self_reduce();
1981
0
    }
1982
30.5k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE15reduction_checkEv
Line
Count
Source
1947
216
{
1948
1949
216
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
36
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
36
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
36
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
36
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
36
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
36
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
36
                                               prime_basis_limb.get_origin_tag() });
1959
36
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
36
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
36
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
36
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
36
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
36
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
36
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
36
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
36
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
36
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
36
        return;
1971
36
    }
1972
1973
180
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
180
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
180
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
180
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
180
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
180
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
180
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
0
        self_reduce();
1981
0
    }
1982
180
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE15reduction_checkEv
Line
Count
Source
1947
763k
{
1948
1949
763k
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
91.2k
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
91.2k
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
91.2k
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
91.2k
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
91.2k
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
91.2k
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
91.2k
                                               prime_basis_limb.get_origin_tag() });
1959
91.2k
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
91.2k
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
91.2k
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
91.2k
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
91.2k
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
91.2k
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
91.2k
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
91.2k
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
91.2k
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
91.2k
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
91.2k
        return;
1971
91.2k
    }
1972
1973
672k
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
672k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
672k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
672k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
672k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
672k
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
672k
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
0
        self_reduce();
1981
0
    }
1982
672k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE15reduction_checkEv
Line
Count
Source
1947
4.89k
{
1948
1949
4.89k
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
864
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
864
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
864
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
864
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
864
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
864
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
864
                                               prime_basis_limb.get_origin_tag() });
1959
864
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
864
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
864
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
864
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
864
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
864
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
864
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
864
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
864
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
864
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
864
        return;
1971
864
    }
1972
1973
4.03k
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
4.03k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
4.03k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
4.03k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
4.03k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
4.03k
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
4.03k
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
0
        self_reduce();
1981
0
    }
1982
4.03k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE15reduction_checkEv
Line
Count
Source
1947
56.4k
{
1948
1949
56.4k
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
6.05k
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
6.05k
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
6.05k
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
6.05k
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
6.05k
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
6.05k
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
6.05k
                                               prime_basis_limb.get_origin_tag() });
1959
6.05k
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
6.05k
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
6.05k
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
6.05k
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
6.05k
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
6.05k
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
6.05k
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
6.05k
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
6.05k
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
6.05k
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
6.05k
        return;
1971
6.05k
    }
1972
1973
50.3k
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
50.3k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
50.3k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
50.3k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
50.3k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
50.3k
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
50.3k
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
0
        self_reduce();
1981
0
    }
1982
50.3k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE15reduction_checkEv
Line
Count
Source
1947
60
{
1948
1949
60
    if (is_constant()) { // this seems not a reduction check, but actually computing the reduction
1950
                         // TODO THIS IS UGLY WHY CAN'T WE JUST DO (*THIS) = REDUCED?
1951
0
        uint256_t reduced_value = (get_value() % modulus_u512).lo;
1952
0
        bigfield reduced(context, uint256_t(reduced_value));
1953
        // Save tags
1954
0
        const auto origin_tags = std::vector({ binary_basis_limbs[0].element.get_origin_tag(),
1955
0
                                               binary_basis_limbs[1].element.get_origin_tag(),
1956
0
                                               binary_basis_limbs[2].element.get_origin_tag(),
1957
0
                                               binary_basis_limbs[3].element.get_origin_tag(),
1958
0
                                               prime_basis_limb.get_origin_tag() });
1959
0
        binary_basis_limbs[0] = reduced.binary_basis_limbs[0];
1960
0
        binary_basis_limbs[1] = reduced.binary_basis_limbs[1];
1961
0
        binary_basis_limbs[2] = reduced.binary_basis_limbs[2];
1962
0
        binary_basis_limbs[3] = reduced.binary_basis_limbs[3];
1963
0
        prime_basis_limb = reduced.prime_basis_limb;
1964
        // Preserve origin tags (useful in simulator)
1965
0
        binary_basis_limbs[0].element.set_origin_tag(origin_tags[0]);
1966
0
        binary_basis_limbs[1].element.set_origin_tag(origin_tags[1]);
1967
0
        binary_basis_limbs[2].element.set_origin_tag(origin_tags[2]);
1968
0
        binary_basis_limbs[3].element.set_origin_tag(origin_tags[3]);
1969
0
        prime_basis_limb.set_origin_tag(origin_tags[4]);
1970
0
        return;
1971
0
    }
1972
1973
60
    uint256_t maximum_limb_value = get_maximum_unreduced_limb_value();
1974
60
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1975
60
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1976
60
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1977
60
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1978
60
    if (get_maximum_value() > get_maximum_unreduced_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
1979
60
        limb_overflow_test_2 || limb_overflow_test_3) {
1980
0
        self_reduce();
1981
0
    }
1982
60
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE15reduction_checkEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE15reduction_checkEv
1983
1984
/**
1985
 * SANITY CHECK on a value that is about to interact with another value
1986
 *
1987
 * @details ASSERTs that the value of all limbs is less than or equal to the prohibited maximum value. Checks that the
1988
 *maximum value of the whole element is also less than a prohibited maximum value
1989
 *
1990
 **/
1991
template <typename Builder, typename T> void bigfield<Builder, T>::sanity_check() const
1992
7.48M
{
1993
1994
7.48M
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
7.48M
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
7.48M
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
7.48M
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
7.48M
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
7.48M
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
7.48M
             limb_overflow_test_2 || limb_overflow_test_3));
2001
7.48M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE12sanity_checkEv
Line
Count
Source
1992
6.86M
{
1993
1994
6.86M
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
6.86M
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
6.86M
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
6.86M
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
6.86M
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
6.86M
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
6.86M
             limb_overflow_test_2 || limb_overflow_test_3));
2001
6.86M
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE12sanity_checkEv
Line
Count
Source
1992
1.51k
{
1993
1994
1.51k
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
1.51k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
1.51k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
1.51k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
1.51k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
1.51k
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
1.51k
             limb_overflow_test_2 || limb_overflow_test_3));
2001
1.51k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE12sanity_checkEv
Line
Count
Source
1992
64
{
1993
1994
64
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
64
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
64
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
64
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
64
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
64
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
64
             limb_overflow_test_2 || limb_overflow_test_3));
2001
64
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E12sanity_checkEv
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE12sanity_checkEv
Line
Count
Source
1992
24.9k
{
1993
1994
24.9k
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
24.9k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
24.9k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
24.9k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
24.9k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
24.9k
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
24.9k
             limb_overflow_test_2 || limb_overflow_test_3));
2001
24.9k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE12sanity_checkEv
Line
Count
Source
1992
278
{
1993
1994
278
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
278
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
278
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
278
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
278
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
278
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
278
             limb_overflow_test_2 || limb_overflow_test_3));
2001
278
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE12sanity_checkEv
Line
Count
Source
1992
545k
{
1993
1994
545k
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
545k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
545k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
545k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
545k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
545k
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
545k
             limb_overflow_test_2 || limb_overflow_test_3));
2001
545k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE12sanity_checkEv
Line
Count
Source
1992
5.18k
{
1993
1994
5.18k
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
5.18k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
5.18k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
5.18k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
5.18k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
5.18k
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
5.18k
             limb_overflow_test_2 || limb_overflow_test_3));
2001
5.18k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE12sanity_checkEv
Line
Count
Source
1992
40.9k
{
1993
1994
40.9k
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
40.9k
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
40.9k
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
40.9k
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
40.9k
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
40.9k
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
40.9k
             limb_overflow_test_2 || limb_overflow_test_3));
2001
40.9k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE12sanity_checkEv
Line
Count
Source
1992
170
{
1993
1994
170
    uint256_t maximum_limb_value = get_prohibited_maximum_limb_value();
1995
170
    bool limb_overflow_test_0 = binary_basis_limbs[0].maximum_value > maximum_limb_value;
1996
170
    bool limb_overflow_test_1 = binary_basis_limbs[1].maximum_value > maximum_limb_value;
1997
170
    bool limb_overflow_test_2 = binary_basis_limbs[2].maximum_value > maximum_limb_value;
1998
170
    bool limb_overflow_test_3 = binary_basis_limbs[3].maximum_value > maximum_limb_value;
1999
170
    ASSERT(!(get_maximum_value() > get_prohibited_maximum_value() || limb_overflow_test_0 || limb_overflow_test_1 ||
2000
170
             limb_overflow_test_2 || limb_overflow_test_3));
2001
170
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE12sanity_checkEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE12sanity_checkEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE12sanity_checkEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE12sanity_checkEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE12sanity_checkEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E12sanity_checkEv
2002
2003
// Underneath performs assert_less_than(modulus)
2004
// create a version with mod 2^t element part in [0,p-1]
2005
// After reducing to size 2^s, we check (p-1)-a is non-negative as integer.
2006
// We perform subtraction using carries on blocks of size 2^b. The operations inside the blocks are done mod r
2007
// Including the effect of carries the operation inside each limb is in the range [-2^b-1,2^{b+1}]
2008
// Assuming this values are all distinct mod r, which happens e.g. if r/2>2^{b+1}, then if all limb values are
2009
// non-negative at the end of subtraction, we know the subtraction result is positive as integers and a<p
2010
template <typename Builder, typename T> void bigfield<Builder, T>::assert_is_in_field() const
2011
509
{
2012
509
    assert_less_than(modulus);
2013
509
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE18assert_is_in_fieldEv
Line
Count
Source
2011
16
{
2012
16
    assert_less_than(modulus);
2013
16
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE18assert_is_in_fieldEv
Line
Count
Source
2011
3
{
2012
3
    assert_less_than(modulus);
2013
3
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE18assert_is_in_fieldEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E18assert_is_in_fieldEv
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE18assert_is_in_fieldEv
Line
Count
Source
2011
11
{
2012
11
    assert_less_than(modulus);
2013
11
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE18assert_is_in_fieldEv
Line
Count
Source
2011
24
{
2012
24
    assert_less_than(modulus);
2013
24
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE18assert_is_in_fieldEv
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE18assert_is_in_fieldEv
Line
Count
Source
2011
432
{
2012
432
    assert_less_than(modulus);
2013
432
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE18assert_is_in_fieldEv
Line
Count
Source
2011
8
{
2012
8
    assert_less_than(modulus);
2013
8
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE18assert_is_in_fieldEv
Line
Count
Source
2011
15
{
2012
15
    assert_less_than(modulus);
2013
15
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE18assert_is_in_fieldEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE18assert_is_in_fieldEv
2014
2015
template <typename Builder, typename T> void bigfield<Builder, T>::assert_less_than(const uint256_t upper_limit) const
2016
676
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
676
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
676
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
0
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
0
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
0
    uint256_t value = get_value().lo;
2031
2032
0
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
0
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
0
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
0
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
0
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
0
    bool borrow_1_value =
2039
0
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
0
    bool borrow_2_value =
2041
0
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
0
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
0
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
0
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
0
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
0
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
0
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
0
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
0
    field_t<Builder> r0 =
2056
0
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
0
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
0
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
0
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
0
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
0
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
0
    r0 = r0.normalize();
2063
0
    r1 = r1.normalize();
2064
0
    r2 = r2.normalize();
2065
0
    r3 = r3.normalize();
2066
676
    if constexpr (HasPlookup<Builder>) {
2067
676
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
676
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
676
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
676
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
676
    } else {
2072
0
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
0
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
0
                                                   "bigfield: assert_less_than range constraint 1.");
2075
0
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
0
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
0
                                                   "bigfield: assert_less_than range constraint 2.");
2078
0
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
0
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
0
                                                   "bigfield: assert_less_than range constraint 3.");
2081
0
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
0
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
0
                                                   "bigfield: assert_less_than range constraint 4.");
2084
0
    }
2085
0
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE16assert_less_thanENS_7numeric9uint256_tE
Line
Count
Source
2016
28
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
28
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
28
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
28
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
28
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
28
    uint256_t value = get_value().lo;
2031
2032
28
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
28
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
28
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
28
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
28
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
28
    bool borrow_1_value =
2039
28
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
28
    bool borrow_2_value =
2041
28
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
28
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
28
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
28
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
28
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
28
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
28
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
28
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
28
    field_t<Builder> r0 =
2056
28
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
28
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
28
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
28
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
28
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
28
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
28
    r0 = r0.normalize();
2063
28
    r1 = r1.normalize();
2064
28
    r2 = r2.normalize();
2065
28
    r3 = r3.normalize();
2066
28
    if constexpr (HasPlookup<Builder>) {
2067
28
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
28
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
28
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
28
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
28
    } else {
2072
28
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
28
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
28
                                                   "bigfield: assert_less_than range constraint 1.");
2075
28
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
28
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
28
                                                   "bigfield: assert_less_than range constraint 2.");
2078
28
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
28
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
28
                                                   "bigfield: assert_less_than range constraint 3.");
2081
28
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
28
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
28
                                                   "bigfield: assert_less_than range constraint 4.");
2084
28
    }
2085
28
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE16assert_less_thanENS_7numeric9uint256_tE
Line
Count
Source
2016
3
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
3
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
3
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
3
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
3
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
3
    uint256_t value = get_value().lo;
2031
2032
3
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
3
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
3
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
3
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
3
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
3
    bool borrow_1_value =
2039
3
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
3
    bool borrow_2_value =
2041
3
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
3
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
3
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
3
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
3
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
3
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
3
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
3
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
3
    field_t<Builder> r0 =
2056
3
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
3
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
3
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
3
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
3
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
3
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
3
    r0 = r0.normalize();
2063
3
    r1 = r1.normalize();
2064
3
    r2 = r2.normalize();
2065
3
    r3 = r3.normalize();
2066
3
    if constexpr (HasPlookup<Builder>) {
2067
3
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
3
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
3
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
3
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
3
    } else {
2072
3
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
3
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
3
                                                   "bigfield: assert_less_than range constraint 1.");
2075
3
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
3
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
3
                                                   "bigfield: assert_less_than range constraint 2.");
2078
3
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
3
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
3
                                                   "bigfield: assert_less_than range constraint 3.");
2081
3
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
3
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
3
                                                   "bigfield: assert_less_than range constraint 4.");
2084
3
    }
2085
3
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE16assert_less_thanENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E16assert_less_thanENS_7numeric9uint256_tE
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE16assert_less_thanENS_7numeric9uint256_tE
Line
Count
Source
2016
11
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
11
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
11
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
11
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
11
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
11
    uint256_t value = get_value().lo;
2031
2032
11
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
11
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
11
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
11
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
11
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
11
    bool borrow_1_value =
2039
11
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
11
    bool borrow_2_value =
2041
11
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
11
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
11
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
11
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
11
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
11
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
11
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
11
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
11
    field_t<Builder> r0 =
2056
11
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
11
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
11
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
11
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
11
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
11
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
11
    r0 = r0.normalize();
2063
11
    r1 = r1.normalize();
2064
11
    r2 = r2.normalize();
2065
11
    r3 = r3.normalize();
2066
11
    if constexpr (HasPlookup<Builder>) {
2067
11
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
11
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
11
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
11
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
11
    } else {
2072
11
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
11
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
11
                                                   "bigfield: assert_less_than range constraint 1.");
2075
11
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
11
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
11
                                                   "bigfield: assert_less_than range constraint 2.");
2078
11
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
11
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
11
                                                   "bigfield: assert_less_than range constraint 3.");
2081
11
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
11
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
11
                                                   "bigfield: assert_less_than range constraint 4.");
2084
11
    }
2085
11
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE16assert_less_thanENS_7numeric9uint256_tE
Line
Count
Source
2016
30
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
30
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
30
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
30
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
30
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
30
    uint256_t value = get_value().lo;
2031
2032
30
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
30
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
30
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
30
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
30
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
30
    bool borrow_1_value =
2039
30
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
30
    bool borrow_2_value =
2041
30
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
30
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
30
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
30
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
30
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
30
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
30
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
30
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
30
    field_t<Builder> r0 =
2056
30
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
30
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
30
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
30
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
30
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
30
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
30
    r0 = r0.normalize();
2063
30
    r1 = r1.normalize();
2064
30
    r2 = r2.normalize();
2065
30
    r3 = r3.normalize();
2066
30
    if constexpr (HasPlookup<Builder>) {
2067
30
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
30
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
30
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
30
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
30
    } else {
2072
30
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
30
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
30
                                                   "bigfield: assert_less_than range constraint 1.");
2075
30
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
30
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
30
                                                   "bigfield: assert_less_than range constraint 2.");
2078
30
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
30
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
30
                                                   "bigfield: assert_less_than range constraint 3.");
2081
30
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
30
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
30
                                                   "bigfield: assert_less_than range constraint 4.");
2084
30
    }
2085
30
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE16assert_less_thanENS_7numeric9uint256_tE
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE16assert_less_thanENS_7numeric9uint256_tE
Line
Count
Source
2016
576
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
576
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
576
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
576
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
576
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
576
    uint256_t value = get_value().lo;
2031
2032
576
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
576
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
576
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
576
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
576
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
576
    bool borrow_1_value =
2039
576
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
576
    bool borrow_2_value =
2041
576
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
576
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
576
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
576
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
576
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
576
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
576
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
576
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
576
    field_t<Builder> r0 =
2056
576
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
576
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
576
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
576
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
576
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
576
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
576
    r0 = r0.normalize();
2063
576
    r1 = r1.normalize();
2064
576
    r2 = r2.normalize();
2065
576
    r3 = r3.normalize();
2066
576
    if constexpr (HasPlookup<Builder>) {
2067
576
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
576
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
576
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
576
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
576
    } else {
2072
576
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
576
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
576
                                                   "bigfield: assert_less_than range constraint 1.");
2075
576
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
576
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
576
                                                   "bigfield: assert_less_than range constraint 2.");
2078
576
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
576
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
576
                                                   "bigfield: assert_less_than range constraint 3.");
2081
576
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
576
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
576
                                                   "bigfield: assert_less_than range constraint 4.");
2084
576
    }
2085
576
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE16assert_less_thanENS_7numeric9uint256_tE
Line
Count
Source
2016
8
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
8
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
8
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
8
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
8
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
8
    uint256_t value = get_value().lo;
2031
2032
8
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
8
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
8
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
8
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
8
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
8
    bool borrow_1_value =
2039
8
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
8
    bool borrow_2_value =
2041
8
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
8
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
8
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
8
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
8
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
8
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
8
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
8
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
8
    field_t<Builder> r0 =
2056
8
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
8
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
8
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
8
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
8
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
8
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
8
    r0 = r0.normalize();
2063
8
    r1 = r1.normalize();
2064
8
    r2 = r2.normalize();
2065
8
    r3 = r3.normalize();
2066
8
    if constexpr (HasPlookup<Builder>) {
2067
8
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
8
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
8
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
8
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
8
    } else {
2072
8
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
8
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
8
                                                   "bigfield: assert_less_than range constraint 1.");
2075
8
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
8
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
8
                                                   "bigfield: assert_less_than range constraint 2.");
2078
8
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
8
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
8
                                                   "bigfield: assert_less_than range constraint 3.");
2081
8
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
8
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
8
                                                   "bigfield: assert_less_than range constraint 4.");
2084
8
    }
2085
8
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE16assert_less_thanENS_7numeric9uint256_tE
Line
Count
Source
2016
20
{
2017
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2018
    // constants are allowed via ASSERT
2019
2020
20
    if (is_constant()) {
2021
0
        ASSERT(get_value() < static_cast<uint512_t>(upper_limit));
2022
0
        return;
2023
0
    }
2024
2025
20
    ASSERT(upper_limit != 0);
2026
    // The circuit checks that limit - this >= 0, so if we are doing a less_than comparison, we need to subtract 1
2027
    // from the limit
2028
20
    uint256_t strict_upper_limit = upper_limit - uint256_t(1);
2029
20
    self_reduce(); // this method in particular enforces limb vals are <2^b - needed for logic described above
2030
20
    uint256_t value = get_value().lo;
2031
2032
20
    const uint256_t upper_limit_value_0 = strict_upper_limit.slice(0, NUM_LIMB_BITS);
2033
20
    const uint256_t upper_limit_value_1 = strict_upper_limit.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2);
2034
20
    const uint256_t upper_limit_value_2 = strict_upper_limit.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3);
2035
20
    const uint256_t upper_limit_value_3 = strict_upper_limit.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4);
2036
2037
20
    bool borrow_0_value = value.slice(0, NUM_LIMB_BITS) > upper_limit_value_0;
2038
20
    bool borrow_1_value =
2039
20
        (value.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2) + uint256_t(borrow_0_value)) > (upper_limit_value_1);
2040
20
    bool borrow_2_value =
2041
20
        (value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3) + uint256_t(borrow_1_value)) > (upper_limit_value_2);
2042
2043
20
    field_t<Builder> upper_limit_0(context, upper_limit_value_0);
2044
20
    field_t<Builder> upper_limit_1(context, upper_limit_value_1);
2045
20
    field_t<Builder> upper_limit_2(context, upper_limit_value_2);
2046
20
    field_t<Builder> upper_limit_3(context, upper_limit_value_3);
2047
20
    bool_t<Builder> borrow_0(witness_t<Builder>(context, borrow_0_value));
2048
20
    bool_t<Builder> borrow_1(witness_t<Builder>(context, borrow_1_value));
2049
20
    bool_t<Builder> borrow_2(witness_t<Builder>(context, borrow_2_value));
2050
    // The way we use borrows here ensures that we are checking that upper_limit - binary_basis > 0.
2051
    // We check that the result in each limb is > 0.
2052
    // If the modulus part in this limb is smaller, we simply borrow the value from the higher limb.
2053
    // The prover can rearrange the borrows the way they like. The important thing is that the borrows are
2054
    // constrained.
2055
20
    field_t<Builder> r0 =
2056
20
        upper_limit_0 - binary_basis_limbs[0].element + static_cast<field_t<Builder>>(borrow_0) * shift_1;
2057
20
    field_t<Builder> r1 = upper_limit_1 - binary_basis_limbs[1].element +
2058
20
                          static_cast<field_t<Builder>>(borrow_1) * shift_1 - static_cast<field_t<Builder>>(borrow_0);
2059
20
    field_t<Builder> r2 = upper_limit_2 - binary_basis_limbs[2].element +
2060
20
                          static_cast<field_t<Builder>>(borrow_2) * shift_1 - static_cast<field_t<Builder>>(borrow_1);
2061
20
    field_t<Builder> r3 = upper_limit_3 - binary_basis_limbs[3].element - static_cast<field_t<Builder>>(borrow_2);
2062
20
    r0 = r0.normalize();
2063
20
    r1 = r1.normalize();
2064
20
    r2 = r2.normalize();
2065
20
    r3 = r3.normalize();
2066
20
    if constexpr (HasPlookup<Builder>) {
2067
20
        context->decompose_into_default_range(r0.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2068
20
        context->decompose_into_default_range(r1.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2069
20
        context->decompose_into_default_range(r2.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2070
20
        context->decompose_into_default_range(r3.get_normalized_witness_index(), static_cast<size_t>(NUM_LIMB_BITS));
2071
20
    } else {
2072
20
        context->decompose_into_base4_accumulators(r0.get_normalized_witness_index(),
2073
20
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2074
20
                                                   "bigfield: assert_less_than range constraint 1.");
2075
20
        context->decompose_into_base4_accumulators(r1.get_normalized_witness_index(),
2076
20
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2077
20
                                                   "bigfield: assert_less_than range constraint 2.");
2078
20
        context->decompose_into_base4_accumulators(r2.get_normalized_witness_index(),
2079
20
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2080
20
                                                   "bigfield: assert_less_than range constraint 3.");
2081
20
        context->decompose_into_base4_accumulators(r3.get_normalized_witness_index(),
2082
20
                                                   static_cast<size_t>(NUM_LIMB_BITS),
2083
20
                                                   "bigfield: assert_less_than range constraint 4.");
2084
20
    }
2085
20
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE16assert_less_thanENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE16assert_less_thanENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE16assert_less_thanENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE16assert_less_thanENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE16assert_less_thanENS_7numeric9uint256_tE
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E16assert_less_thanENS_7numeric9uint256_tE
2086
2087
// check elements are equal mod p by proving their integer difference is a multiple of p.
2088
// This relies on the minus operator for a-b increasing a by a multiple of p large enough so diff is non-negative
2089
// When one of the elements is a constant and another is a witness we check equality of limbs, so if the witness
2090
// bigfield element is in an unreduced form, it needs to be reduced first. We don't have automatice reduced form
2091
// detection for now, so it is up to the circuit writer to detect this
2092
template <typename Builder, typename T> void bigfield<Builder, T>::assert_equal(const bigfield& other) const
2093
504
{
2094
504
    Builder* ctx = this->context ? this->context : other.context;
2095
2096
504
    if (is_constant() && other.is_constant()) {
2097
0
        std::cerr << "bigfield: calling assert equal on 2 CONSTANT bigfield elements...is this intended?" << std::endl;
2098
0
        ASSERT(get_value() == other.get_value()); // We expect constants to be less than the target modulus
2099
0
        return;
2100
504
    } else if (other.is_constant()) {
2101
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/998): Something is fishy here
2102
        // evaluate a strict equality - make sure *this is reduced first, or an honest prover
2103
        // might not be able to satisfy these constraints.
2104
36
        field_t<Builder> t0 = (binary_basis_limbs[0].element - other.binary_basis_limbs[0].element);
2105
36
        field_t<Builder> t1 = (binary_basis_limbs[1].element - other.binary_basis_limbs[1].element);
2106
36
        field_t<Builder> t2 = (binary_basis_limbs[2].element - other.binary_basis_limbs[2].element);
2107
36
        field_t<Builder> t3 = (binary_basis_limbs[3].element - other.binary_basis_limbs[3].element);
2108
36
        field_t<Builder> t4 = (prime_basis_limb - other.prime_basis_limb);
2109
36
        t0.assert_is_zero();
2110
36
        t1.assert_is_zero();
2111
36
        t2.assert_is_zero();
2112
36
        t3.assert_is_zero();
2113
36
        t4.assert_is_zero();
2114
36
        return;
2115
468
    } else if (is_constant()) {
2116
0
        other.assert_equal(*this);
2117
0
        return;
2118
468
    } else {
2119
2120
468
        bigfield diff = *this - other;
2121
468
        const uint512_t diff_val = diff.get_value();
2122
468
        const uint512_t modulus(target_basis.modulus);
2123
2124
468
        const auto [quotient_512, remainder_512] = (diff_val).divmod(modulus);
2125
468
        if (remainder_512 != 0) {
2126
9
            std::cerr << "bigfield: remainder not zero!" << std::endl;
2127
9
        }
2128
468
        bigfield quotient;
2129
2130
468
        const size_t num_quotient_bits = get_quotient_max_bits({ 0 });
2131
468
        quotient = bigfield(witness_t(ctx, fr(quotient_512.slice(0, NUM_LIMB_BITS * 2).lo)),
2132
468
                            witness_t(ctx, fr(quotient_512.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 4).lo)),
2133
468
                            false,
2134
468
                            num_quotient_bits);
2135
468
        unsafe_evaluate_multiply_add(diff, { one() }, {}, quotient, { zero() });
2136
468
    }
2137
504
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE12assert_equalERKS6_
Line
Count
Source
2093
172
{
2094
172
    Builder* ctx = this->context ? this->context : other.context;
2095
2096
172
    if (is_constant() && other.is_constant()) {
2097
0
        std::cerr << "bigfield: calling assert equal on 2 CONSTANT bigfield elements...is this intended?" << std::endl;
2098
0
        ASSERT(get_value() == other.get_value()); // We expect constants to be less than the target modulus
2099
0
        return;
2100
172
    } else if (other.is_constant()) {
2101
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/998): Something is fishy here
2102
        // evaluate a strict equality - make sure *this is reduced first, or an honest prover
2103
        // might not be able to satisfy these constraints.
2104
36
        field_t<Builder> t0 = (binary_basis_limbs[0].element - other.binary_basis_limbs[0].element);
2105
36
        field_t<Builder> t1 = (binary_basis_limbs[1].element - other.binary_basis_limbs[1].element);
2106
36
        field_t<Builder> t2 = (binary_basis_limbs[2].element - other.binary_basis_limbs[2].element);
2107
36
        field_t<Builder> t3 = (binary_basis_limbs[3].element - other.binary_basis_limbs[3].element);
2108
36
        field_t<Builder> t4 = (prime_basis_limb - other.prime_basis_limb);
2109
36
        t0.assert_is_zero();
2110
36
        t1.assert_is_zero();
2111
36
        t2.assert_is_zero();
2112
36
        t3.assert_is_zero();
2113
36
        t4.assert_is_zero();
2114
36
        return;
2115
136
    } else if (is_constant()) {
2116
0
        other.assert_equal(*this);
2117
0
        return;
2118
136
    } else {
2119
2120
136
        bigfield diff = *this - other;
2121
136
        const uint512_t diff_val = diff.get_value();
2122
136
        const uint512_t modulus(target_basis.modulus);
2123
2124
136
        const auto [quotient_512, remainder_512] = (diff_val).divmod(modulus);
2125
136
        if (remainder_512 != 0) {
2126
9
            std::cerr << "bigfield: remainder not zero!" << std::endl;
2127
9
        }
2128
136
        bigfield quotient;
2129
2130
136
        const size_t num_quotient_bits = get_quotient_max_bits({ 0 });
2131
136
        quotient = bigfield(witness_t(ctx, fr(quotient_512.slice(0, NUM_LIMB_BITS * 2).lo)),
2132
136
                            witness_t(ctx, fr(quotient_512.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 4).lo)),
2133
136
                            false,
2134
136
                            num_quotient_bits);
2135
136
        unsafe_evaluate_multiply_add(diff, { one() }, {}, quotient, { zero() });
2136
136
    }
2137
172
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE12assert_equalERKS6_
Line
Count
Source
2093
322
{
2094
322
    Builder* ctx = this->context ? this->context : other.context;
2095
2096
322
    if (is_constant() && other.is_constant()) {
2097
0
        std::cerr << "bigfield: calling assert equal on 2 CONSTANT bigfield elements...is this intended?" << std::endl;
2098
0
        ASSERT(get_value() == other.get_value()); // We expect constants to be less than the target modulus
2099
0
        return;
2100
322
    } else if (other.is_constant()) {
2101
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/998): Something is fishy here
2102
        // evaluate a strict equality - make sure *this is reduced first, or an honest prover
2103
        // might not be able to satisfy these constraints.
2104
0
        field_t<Builder> t0 = (binary_basis_limbs[0].element - other.binary_basis_limbs[0].element);
2105
0
        field_t<Builder> t1 = (binary_basis_limbs[1].element - other.binary_basis_limbs[1].element);
2106
0
        field_t<Builder> t2 = (binary_basis_limbs[2].element - other.binary_basis_limbs[2].element);
2107
0
        field_t<Builder> t3 = (binary_basis_limbs[3].element - other.binary_basis_limbs[3].element);
2108
0
        field_t<Builder> t4 = (prime_basis_limb - other.prime_basis_limb);
2109
0
        t0.assert_is_zero();
2110
0
        t1.assert_is_zero();
2111
0
        t2.assert_is_zero();
2112
0
        t3.assert_is_zero();
2113
0
        t4.assert_is_zero();
2114
0
        return;
2115
322
    } else if (is_constant()) {
2116
0
        other.assert_equal(*this);
2117
0
        return;
2118
322
    } else {
2119
2120
322
        bigfield diff = *this - other;
2121
322
        const uint512_t diff_val = diff.get_value();
2122
322
        const uint512_t modulus(target_basis.modulus);
2123
2124
322
        const auto [quotient_512, remainder_512] = (diff_val).divmod(modulus);
2125
322
        if (remainder_512 != 0) {
2126
0
            std::cerr << "bigfield: remainder not zero!" << std::endl;
2127
0
        }
2128
322
        bigfield quotient;
2129
2130
322
        const size_t num_quotient_bits = get_quotient_max_bits({ 0 });
2131
322
        quotient = bigfield(witness_t(ctx, fr(quotient_512.slice(0, NUM_LIMB_BITS * 2).lo)),
2132
322
                            witness_t(ctx, fr(quotient_512.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 4).lo)),
2133
322
                            false,
2134
322
                            num_quotient_bits);
2135
322
        unsafe_evaluate_multiply_add(diff, { one() }, {}, quotient, { zero() });
2136
322
    }
2137
322
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE12assert_equalERKS8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E12assert_equalERKS7_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE12assert_equalERKS7_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE12assert_equalERKS7_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE12assert_equalERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE12assert_equalERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE12assert_equalERKS7_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE12assert_equalERKS7_
Line
Count
Source
2093
10
{
2094
10
    Builder* ctx = this->context ? this->context : other.context;
2095
2096
10
    if (is_constant() && other.is_constant()) {
2097
0
        std::cerr << "bigfield: calling assert equal on 2 CONSTANT bigfield elements...is this intended?" << std::endl;
2098
0
        ASSERT(get_value() == other.get_value()); // We expect constants to be less than the target modulus
2099
0
        return;
2100
10
    } else if (other.is_constant()) {
2101
        // TODO(https://github.com/AztecProtocol/barretenberg/issues/998): Something is fishy here
2102
        // evaluate a strict equality - make sure *this is reduced first, or an honest prover
2103
        // might not be able to satisfy these constraints.
2104
0
        field_t<Builder> t0 = (binary_basis_limbs[0].element - other.binary_basis_limbs[0].element);
2105
0
        field_t<Builder> t1 = (binary_basis_limbs[1].element - other.binary_basis_limbs[1].element);
2106
0
        field_t<Builder> t2 = (binary_basis_limbs[2].element - other.binary_basis_limbs[2].element);
2107
0
        field_t<Builder> t3 = (binary_basis_limbs[3].element - other.binary_basis_limbs[3].element);
2108
0
        field_t<Builder> t4 = (prime_basis_limb - other.prime_basis_limb);
2109
0
        t0.assert_is_zero();
2110
0
        t1.assert_is_zero();
2111
0
        t2.assert_is_zero();
2112
0
        t3.assert_is_zero();
2113
0
        t4.assert_is_zero();
2114
0
        return;
2115
10
    } else if (is_constant()) {
2116
0
        other.assert_equal(*this);
2117
0
        return;
2118
10
    } else {
2119
2120
10
        bigfield diff = *this - other;
2121
10
        const uint512_t diff_val = diff.get_value();
2122
10
        const uint512_t modulus(target_basis.modulus);
2123
2124
10
        const auto [quotient_512, remainder_512] = (diff_val).divmod(modulus);
2125
10
        if (remainder_512 != 0) {
2126
0
            std::cerr << "bigfield: remainder not zero!" << std::endl;
2127
0
        }
2128
10
        bigfield quotient;
2129
2130
10
        const size_t num_quotient_bits = get_quotient_max_bits({ 0 });
2131
10
        quotient = bigfield(witness_t(ctx, fr(quotient_512.slice(0, NUM_LIMB_BITS * 2).lo)),
2132
10
                            witness_t(ctx, fr(quotient_512.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 4).lo)),
2133
10
                            false,
2134
10
                            num_quotient_bits);
2135
10
        unsafe_evaluate_multiply_add(diff, { one() }, {}, quotient, { zero() });
2136
10
    }
2137
10
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE12assert_equalERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE12assert_equalERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE12assert_equalERKS6_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE12assert_equalERKS6_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE12assert_equalERKS8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E12assert_equalERKS7_
2138
2139
// construct a proof that points are different mod p, when they are different mod r
2140
// WARNING: This method doesn't have perfect completeness - for points equal mod r (or with certain difference kp
2141
// mod r) but different mod p, you can't construct a proof. The chances of an honest prover running afoul of this
2142
// condition are extremely small (TODO: compute probability) Note also that the number of constraints depends on how
2143
// much the values have overflown beyond p e.g. due to an addition chain The function is based on the following.
2144
// Suppose a-b = 0 mod p. Then a-b = k*p for k in a range [-R,L] such that L*p>= a, R*p>=b. And also a-b = k*p mod r
2145
// for such k. Thus we can verify a-b is non-zero mod p by taking the product of such values (a-b-kp) and showing
2146
// it's non-zero mod r
2147
template <typename Builder, typename T> void bigfield<Builder, T>::assert_is_not_equal(const bigfield& other) const
2148
350k
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
701k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
701k
        uint512_t target = target_modulus;
2152
701k
        size_t overload_count = 0;
2153
1.40M
        while (target <= maximum_value) {
2154
701k
            ++overload_count;
2155
701k
            target += target_modulus;
2156
701k
        }
2157
701k
        return overload_count;
2158
701k
    };
_ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE19assert_is_not_equalERKS6_ENKUlRKNS_7numeric5uintxINS9_9uint256_tEEEE_clESE_
Line
Count
Source
2150
668k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
668k
        uint512_t target = target_modulus;
2152
668k
        size_t overload_count = 0;
2153
1.33M
        while (target <= maximum_value) {
2154
668k
            ++overload_count;
2155
668k
            target += target_modulus;
2156
668k
        }
2157
668k
        return overload_count;
2158
668k
    };
Unexecuted instantiation: _ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE19assert_is_not_equalERKS6_ENKUlRKNS_7numeric5uintxINS9_9uint256_tEEEE_clESE_
Unexecuted instantiation: _ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE19assert_is_not_equalERKS8_ENKUlRKNS_7numeric5uintxINSB_9uint256_tEEEE_clESG_
Unexecuted instantiation: _ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E19assert_is_not_equalERKS7_ENKUlRKNS_7numeric5uintxINSA_9uint256_tEEEE_clESF_
_ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE19assert_is_not_equalERKS7_ENKUlRKNS_7numeric5uintxINSA_9uint256_tEEEE_clESF_
Line
Count
Source
2150
1.22k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
1.22k
        uint512_t target = target_modulus;
2152
1.22k
        size_t overload_count = 0;
2153
2.44k
        while (target <= maximum_value) {
2154
1.22k
            ++overload_count;
2155
1.22k
            target += target_modulus;
2156
1.22k
        }
2157
1.22k
        return overload_count;
2158
1.22k
    };
_ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE19assert_is_not_equalERKS7_ENKUlRKNS_7numeric5uintxINSA_9uint256_tEEEE_clESF_
Line
Count
Source
2150
48
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
48
        uint512_t target = target_modulus;
2152
48
        size_t overload_count = 0;
2153
72
        while (target <= maximum_value) {
2154
24
            ++overload_count;
2155
24
            target += target_modulus;
2156
24
        }
2157
48
        return overload_count;
2158
48
    };
_ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE19assert_is_not_equalERKS9_ENKUlRKNS_7numeric5uintxINSC_9uint256_tEEEE_clESH_
Line
Count
Source
2150
28.5k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
28.5k
        uint512_t target = target_modulus;
2152
28.5k
        size_t overload_count = 0;
2153
57.0k
        while (target <= maximum_value) {
2154
28.5k
            ++overload_count;
2155
28.5k
            target += target_modulus;
2156
28.5k
        }
2157
28.5k
        return overload_count;
2158
28.5k
    };
_ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE19assert_is_not_equalERKS9_ENKUlRKNS_7numeric5uintxINSC_9uint256_tEEEE_clESH_
Line
Count
Source
2150
576
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
576
        uint512_t target = target_modulus;
2152
576
        size_t overload_count = 0;
2153
864
        while (target <= maximum_value) {
2154
288
            ++overload_count;
2155
288
            target += target_modulus;
2156
288
        }
2157
576
        return overload_count;
2158
576
    };
_ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE19assert_is_not_equalERKS7_ENKUlRKNS_7numeric5uintxINSA_9uint256_tEEEE_clESF_
Line
Count
Source
2150
2.57k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
2.57k
        uint512_t target = target_modulus;
2152
2.57k
        size_t overload_count = 0;
2153
5.13k
        while (target <= maximum_value) {
2154
2.56k
            ++overload_count;
2155
2.56k
            target += target_modulus;
2156
2.56k
        }
2157
2.57k
        return overload_count;
2158
2.57k
    };
_ZZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE19assert_is_not_equalERKS7_ENKUlRKNS_7numeric5uintxINSA_9uint256_tEEEE_clESF_
Line
Count
Source
2150
36
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
36
        uint512_t target = target_modulus;
2152
36
        size_t overload_count = 0;
2153
54
        while (target <= maximum_value) {
2154
18
            ++overload_count;
2155
18
            target += target_modulus;
2156
18
        }
2157
36
        return overload_count;
2158
36
    };
Unexecuted instantiation: _ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE19assert_is_not_equalERKS9_ENKUlRKNS_7numeric5uintxINSC_9uint256_tEEEE_clESH_
Unexecuted instantiation: _ZZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE19assert_is_not_equalERKS9_ENKUlRKNS_7numeric5uintxINSC_9uint256_tEEEE_clESH_
2159
350k
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
350k
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
350k
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
350k
    auto diff = base_diff;
2169
350k
    field_t<Builder> prime_basis(get_context(), modulus);
2170
350k
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
706k
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
355k
        diff = diff * (base_diff - prime_basis_accumulator);
2175
355k
        prime_basis_accumulator += prime_basis;
2176
355k
    }
2177
350k
    prime_basis_accumulator = prime_basis;
2178
695k
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
345k
        diff = diff * (base_diff + prime_basis_accumulator);
2180
345k
        prime_basis_accumulator += prime_basis;
2181
345k
    }
2182
350k
    diff.assert_is_not_zero();
2183
350k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE19assert_is_not_equalERKS6_
Line
Count
Source
2148
334k
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
334k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
334k
        uint512_t target = target_modulus;
2152
334k
        size_t overload_count = 0;
2153
334k
        while (target <= maximum_value) {
2154
334k
            ++overload_count;
2155
334k
            target += target_modulus;
2156
334k
        }
2157
334k
        return overload_count;
2158
334k
    };
2159
334k
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
334k
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
334k
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
334k
    auto diff = base_diff;
2169
334k
    field_t<Builder> prime_basis(get_context(), modulus);
2170
334k
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
673k
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
339k
        diff = diff * (base_diff - prime_basis_accumulator);
2175
339k
        prime_basis_accumulator += prime_basis;
2176
339k
    }
2177
334k
    prime_basis_accumulator = prime_basis;
2178
663k
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
329k
        diff = diff * (base_diff + prime_basis_accumulator);
2180
329k
        prime_basis_accumulator += prime_basis;
2181
329k
    }
2182
334k
    diff.assert_is_not_zero();
2183
334k
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE19assert_is_not_equalERKS6_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE19assert_is_not_equalERKS8_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E19assert_is_not_equalERKS7_
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE19assert_is_not_equalERKS7_
Line
Count
Source
2148
610
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
610
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
610
        uint512_t target = target_modulus;
2152
610
        size_t overload_count = 0;
2153
610
        while (target <= maximum_value) {
2154
610
            ++overload_count;
2155
610
            target += target_modulus;
2156
610
        }
2157
610
        return overload_count;
2158
610
    };
2159
610
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
610
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
610
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
610
    auto diff = base_diff;
2169
610
    field_t<Builder> prime_basis(get_context(), modulus);
2170
610
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
1.22k
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
610
        diff = diff * (base_diff - prime_basis_accumulator);
2175
610
        prime_basis_accumulator += prime_basis;
2176
610
    }
2177
610
    prime_basis_accumulator = prime_basis;
2178
1.22k
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
610
        diff = diff * (base_diff + prime_basis_accumulator);
2180
610
        prime_basis_accumulator += prime_basis;
2181
610
    }
2182
610
    diff.assert_is_not_zero();
2183
610
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE19assert_is_not_equalERKS7_
Line
Count
Source
2148
24
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
24
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
24
        uint512_t target = target_modulus;
2152
24
        size_t overload_count = 0;
2153
24
        while (target <= maximum_value) {
2154
24
            ++overload_count;
2155
24
            target += target_modulus;
2156
24
        }
2157
24
        return overload_count;
2158
24
    };
2159
24
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
24
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
24
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
24
    auto diff = base_diff;
2169
24
    field_t<Builder> prime_basis(get_context(), modulus);
2170
24
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
48
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
24
        diff = diff * (base_diff - prime_basis_accumulator);
2175
24
        prime_basis_accumulator += prime_basis;
2176
24
    }
2177
24
    prime_basis_accumulator = prime_basis;
2178
24
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
0
        diff = diff * (base_diff + prime_basis_accumulator);
2180
0
        prime_basis_accumulator += prime_basis;
2181
0
    }
2182
24
    diff.assert_is_not_zero();
2183
24
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE19assert_is_not_equalERKS9_
Line
Count
Source
2148
14.2k
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
14.2k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
14.2k
        uint512_t target = target_modulus;
2152
14.2k
        size_t overload_count = 0;
2153
14.2k
        while (target <= maximum_value) {
2154
14.2k
            ++overload_count;
2155
14.2k
            target += target_modulus;
2156
14.2k
        }
2157
14.2k
        return overload_count;
2158
14.2k
    };
2159
14.2k
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
14.2k
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
14.2k
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
14.2k
    auto diff = base_diff;
2169
14.2k
    field_t<Builder> prime_basis(get_context(), modulus);
2170
14.2k
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
28.5k
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
14.2k
        diff = diff * (base_diff - prime_basis_accumulator);
2175
14.2k
        prime_basis_accumulator += prime_basis;
2176
14.2k
    }
2177
14.2k
    prime_basis_accumulator = prime_basis;
2178
28.5k
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
14.2k
        diff = diff * (base_diff + prime_basis_accumulator);
2180
14.2k
        prime_basis_accumulator += prime_basis;
2181
14.2k
    }
2182
14.2k
    diff.assert_is_not_zero();
2183
14.2k
}
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE19assert_is_not_equalERKS9_
Line
Count
Source
2148
288
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
288
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
288
        uint512_t target = target_modulus;
2152
288
        size_t overload_count = 0;
2153
288
        while (target <= maximum_value) {
2154
288
            ++overload_count;
2155
288
            target += target_modulus;
2156
288
        }
2157
288
        return overload_count;
2158
288
    };
2159
288
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
288
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
288
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
288
    auto diff = base_diff;
2169
288
    field_t<Builder> prime_basis(get_context(), modulus);
2170
288
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
576
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
288
        diff = diff * (base_diff - prime_basis_accumulator);
2175
288
        prime_basis_accumulator += prime_basis;
2176
288
    }
2177
288
    prime_basis_accumulator = prime_basis;
2178
288
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
0
        diff = diff * (base_diff + prime_basis_accumulator);
2180
0
        prime_basis_accumulator += prime_basis;
2181
0
    }
2182
288
    diff.assert_is_not_zero();
2183
288
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE19assert_is_not_equalERKS7_
Line
Count
Source
2148
1.28k
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
1.28k
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
1.28k
        uint512_t target = target_modulus;
2152
1.28k
        size_t overload_count = 0;
2153
1.28k
        while (target <= maximum_value) {
2154
1.28k
            ++overload_count;
2155
1.28k
            target += target_modulus;
2156
1.28k
        }
2157
1.28k
        return overload_count;
2158
1.28k
    };
2159
1.28k
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
1.28k
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
1.28k
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
1.28k
    auto diff = base_diff;
2169
1.28k
    field_t<Builder> prime_basis(get_context(), modulus);
2170
1.28k
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
2.56k
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
1.27k
        diff = diff * (base_diff - prime_basis_accumulator);
2175
1.27k
        prime_basis_accumulator += prime_basis;
2176
1.27k
    }
2177
1.28k
    prime_basis_accumulator = prime_basis;
2178
2.57k
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
1.28k
        diff = diff * (base_diff + prime_basis_accumulator);
2180
1.28k
        prime_basis_accumulator += prime_basis;
2181
1.28k
    }
2182
1.28k
    diff.assert_is_not_zero();
2183
1.28k
}
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE19assert_is_not_equalERKS7_
Line
Count
Source
2148
18
{
2149
    // Why would we use this for 2 constants? Turns out, in biggroup
2150
18
    const auto get_overload_count = [target_modulus = modulus_u512](const uint512_t& maximum_value) {
2151
18
        uint512_t target = target_modulus;
2152
18
        size_t overload_count = 0;
2153
18
        while (target <= maximum_value) {
2154
18
            ++overload_count;
2155
18
            target += target_modulus;
2156
18
        }
2157
18
        return overload_count;
2158
18
    };
2159
18
    const size_t lhs_overload_count = get_overload_count(get_maximum_value());
2160
18
    const size_t rhs_overload_count = get_overload_count(other.get_maximum_value());
2161
2162
    // if (a == b) then (a == b mod n)
2163
    // to save gates, we only check that (a == b mod n)
2164
2165
    // if numeric val of a = a' + p.q
2166
    // we want to check (a' + p.q == b mod n)
2167
18
    const field_t<Builder> base_diff = prime_basis_limb - other.prime_basis_limb;
2168
18
    auto diff = base_diff;
2169
18
    field_t<Builder> prime_basis(get_context(), modulus);
2170
18
    field_t<Builder> prime_basis_accumulator = prime_basis;
2171
    // Each loop iteration adds 1 gate
2172
    // (prime_basis and prime_basis accumulator are constant so only the * operator adds a gate)
2173
36
    for (size_t i = 0; i < lhs_overload_count; ++i) {
2174
18
        diff = diff * (base_diff - prime_basis_accumulator);
2175
18
        prime_basis_accumulator += prime_basis;
2176
18
    }
2177
18
    prime_basis_accumulator = prime_basis;
2178
18
    for (size_t i = 0; i < rhs_overload_count; ++i) {
2179
0
        diff = diff * (base_diff + prime_basis_accumulator);
2180
0
        prime_basis_accumulator += prime_basis;
2181
0
    }
2182
18
    diff.assert_is_not_zero();
2183
18
}
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE19assert_is_not_equalERKS9_
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE19assert_is_not_equalERKS9_
2184
2185
// We reduce an element's mod 2^t representation (t=4*NUM_LIMB_BITS) to size 2^s for smallest s with 2^s>p
2186
// This is much cheaper than actually reducing mod p and suffices for addition chains (where we just need not to
2187
// overflow 2^t) We also reduce any "spillage" inside the first 3 limbs, so that their range is NUM_LIMB_BITS and
2188
// not larger
2189
template <typename Builder, typename T> void bigfield<Builder, T>::self_reduce() const
2190
2.05k
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
2.05k
    if (is_constant()) {
2194
1
        return;
2195
1
    }
2196
2.05k
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
2.05k
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
2.05k
    bigfield quotient(context);
2201
2202
2.05k
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
2.05k
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
2.05k
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
1.35k
        ++maximum_quotient_bits;
2206
1.35k
    }
2207
2208
2.05k
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
0
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
0
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
2.05k
    if constexpr (HasPlookup<Builder>) {
2212
2.05k
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
2.05k
                                              static_cast<size_t>(maximum_quotient_bits));
2214
2.05k
    } else {
2215
0
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
0
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
0
                                                   "bigfield: quotient_limb too large.");
2218
0
    }
2219
2220
2.05k
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
0
           get_maximum_crt_product());
2222
0
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
0
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
0
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
0
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
0
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
0
    bigfield remainder = bigfield(
2229
0
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
0
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
0
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
0
    binary_basis_limbs[0] =
2234
0
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
0
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
0
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
0
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
0
    prime_basis_limb = remainder.prime_basis_limb;
2239
0
    set_origin_tag(new_tag);
2240
0
} // namespace stdlib
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE11self_reduceEv
Line
Count
Source
2190
1.22k
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
1.22k
    if (is_constant()) {
2194
1
        return;
2195
1
    }
2196
1.22k
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
1.22k
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
1.22k
    bigfield quotient(context);
2201
2202
1.22k
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
1.22k
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
1.22k
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
533
        ++maximum_quotient_bits;
2206
533
    }
2207
2208
1.22k
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
1.22k
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
1.22k
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
1.22k
    if constexpr (HasPlookup<Builder>) {
2212
1.22k
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
1.22k
                                              static_cast<size_t>(maximum_quotient_bits));
2214
1.22k
    } else {
2215
1.22k
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
1.22k
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
1.22k
                                                   "bigfield: quotient_limb too large.");
2218
1.22k
    }
2219
2220
1.22k
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
1.22k
           get_maximum_crt_product());
2222
1.22k
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
1.22k
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
1.22k
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
1.22k
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
1.22k
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
1.22k
    bigfield remainder = bigfield(
2229
1.22k
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
1.22k
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
1.22k
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
1.22k
    binary_basis_limbs[0] =
2234
1.22k
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
1.22k
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
1.22k
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
1.22k
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
1.22k
    prime_basis_limb = remainder.prime_basis_limb;
2239
1.22k
    set_origin_tag(new_tag);
2240
1.22k
} // namespace stdlib
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE11self_reduceEv
Line
Count
Source
2190
18
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
18
    if (is_constant()) {
2194
0
        return;
2195
0
    }
2196
18
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
18
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
18
    bigfield quotient(context);
2201
2202
18
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
18
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
18
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
13
        ++maximum_quotient_bits;
2206
13
    }
2207
2208
18
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
18
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
18
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
18
    if constexpr (HasPlookup<Builder>) {
2212
18
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
18
                                              static_cast<size_t>(maximum_quotient_bits));
2214
18
    } else {
2215
18
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
18
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
18
                                                   "bigfield: quotient_limb too large.");
2218
18
    }
2219
2220
18
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
18
           get_maximum_crt_product());
2222
18
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
18
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
18
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
18
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
18
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
18
    bigfield remainder = bigfield(
2229
18
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
18
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
18
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
18
    binary_basis_limbs[0] =
2234
18
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
18
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
18
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
18
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
18
    prime_basis_limb = remainder.prime_basis_limb;
2239
18
    set_origin_tag(new_tag);
2240
18
} // namespace stdlib
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE11self_reduceEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E11self_reduceEv
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE11self_reduceEv
Line
Count
Source
2190
22
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
22
    if (is_constant()) {
2194
0
        return;
2195
0
    }
2196
22
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
22
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
22
    bigfield quotient(context);
2201
2202
22
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
22
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
22
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
19
        ++maximum_quotient_bits;
2206
19
    }
2207
2208
22
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
22
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
22
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
22
    if constexpr (HasPlookup<Builder>) {
2212
22
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
22
                                              static_cast<size_t>(maximum_quotient_bits));
2214
22
    } else {
2215
22
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
22
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
22
                                                   "bigfield: quotient_limb too large.");
2218
22
    }
2219
2220
22
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
22
           get_maximum_crt_product());
2222
22
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
22
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
22
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
22
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
22
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
22
    bigfield remainder = bigfield(
2229
22
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
22
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
22
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
22
    binary_basis_limbs[0] =
2234
22
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
22
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
22
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
22
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
22
    prime_basis_limb = remainder.prime_basis_limb;
2239
22
    set_origin_tag(new_tag);
2240
22
} // namespace stdlib
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE11self_reduceEv
Line
Count
Source
2190
36
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
36
    if (is_constant()) {
2194
0
        return;
2195
0
    }
2196
36
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
36
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
36
    bigfield quotient(context);
2201
2202
36
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
36
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
36
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
33
        ++maximum_quotient_bits;
2206
33
    }
2207
2208
36
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
36
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
36
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
36
    if constexpr (HasPlookup<Builder>) {
2212
36
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
36
                                              static_cast<size_t>(maximum_quotient_bits));
2214
36
    } else {
2215
36
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
36
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
36
                                                   "bigfield: quotient_limb too large.");
2218
36
    }
2219
2220
36
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
36
           get_maximum_crt_product());
2222
36
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
36
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
36
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
36
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
36
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
36
    bigfield remainder = bigfield(
2229
36
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
36
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
36
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
36
    binary_basis_limbs[0] =
2234
36
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
36
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
36
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
36
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
36
    prime_basis_limb = remainder.prime_basis_limb;
2239
36
    set_origin_tag(new_tag);
2240
36
} // namespace stdlib
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE11self_reduceEv
Line
Count
Source
2190
144
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
144
    if (is_constant()) {
2194
0
        return;
2195
0
    }
2196
144
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
144
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
144
    bigfield quotient(context);
2201
2202
144
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
144
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
144
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
144
        ++maximum_quotient_bits;
2206
144
    }
2207
2208
144
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
144
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
144
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
144
    if constexpr (HasPlookup<Builder>) {
2212
144
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
144
                                              static_cast<size_t>(maximum_quotient_bits));
2214
144
    } else {
2215
144
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
144
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
144
                                                   "bigfield: quotient_limb too large.");
2218
144
    }
2219
2220
144
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
144
           get_maximum_crt_product());
2222
144
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
144
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
144
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
144
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
144
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
144
    bigfield remainder = bigfield(
2229
144
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
144
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
144
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
144
    binary_basis_limbs[0] =
2234
144
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
144
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
144
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
144
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
144
    prime_basis_limb = remainder.prime_basis_limb;
2239
144
    set_origin_tag(new_tag);
2240
144
} // namespace stdlib
_ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE11self_reduceEv
Line
Count
Source
2190
576
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
576
    if (is_constant()) {
2194
0
        return;
2195
0
    }
2196
576
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
576
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
576
    bigfield quotient(context);
2201
2202
576
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
576
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
576
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
576
        ++maximum_quotient_bits;
2206
576
    }
2207
2208
576
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
576
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
576
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
576
    if constexpr (HasPlookup<Builder>) {
2212
576
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
576
                                              static_cast<size_t>(maximum_quotient_bits));
2214
576
    } else {
2215
576
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
576
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
576
                                                   "bigfield: quotient_limb too large.");
2218
576
    }
2219
2220
576
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
576
           get_maximum_crt_product());
2222
576
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
576
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
576
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
576
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
576
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
576
    bigfield remainder = bigfield(
2229
576
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
576
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
576
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
576
    binary_basis_limbs[0] =
2234
576
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
576
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
576
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
576
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
576
    prime_basis_limb = remainder.prime_basis_limb;
2239
576
    set_origin_tag(new_tag);
2240
576
} // namespace stdlib
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE11self_reduceEv
Line
Count
Source
2190
13
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
13
    if (is_constant()) {
2194
0
        return;
2195
0
    }
2196
13
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
13
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
13
    bigfield quotient(context);
2201
2202
13
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
13
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
13
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
13
        ++maximum_quotient_bits;
2206
13
    }
2207
2208
13
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
13
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
13
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
13
    if constexpr (HasPlookup<Builder>) {
2212
13
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
13
                                              static_cast<size_t>(maximum_quotient_bits));
2214
13
    } else {
2215
13
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
13
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
13
                                                   "bigfield: quotient_limb too large.");
2218
13
    }
2219
2220
13
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
13
           get_maximum_crt_product());
2222
13
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
13
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
13
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
13
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
13
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
13
    bigfield remainder = bigfield(
2229
13
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
13
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
13
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
13
    binary_basis_limbs[0] =
2234
13
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
13
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
13
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
13
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
13
    prime_basis_limb = remainder.prime_basis_limb;
2239
13
    set_origin_tag(new_tag);
2240
13
} // namespace stdlib
_ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE11self_reduceEv
Line
Count
Source
2190
20
{
2191
    // Warning: this assumes we have run circuit construction at least once in debug mode where large non reduced
2192
    // constants are disallowed via ASSERT
2193
20
    if (is_constant()) {
2194
0
        return;
2195
0
    }
2196
20
    OriginTag new_tag = get_origin_tag();
2197
    // TODO: handle situation where some limbs are constant and others are not constant
2198
20
    const auto [quotient_value, remainder_value] = get_value().divmod(target_basis.modulus);
2199
2200
20
    bigfield quotient(context);
2201
2202
20
    uint512_t maximum_quotient_size = get_maximum_value() / target_basis.modulus;
2203
20
    uint64_t maximum_quotient_bits = maximum_quotient_size.get_msb() + 1;
2204
20
    if ((maximum_quotient_bits & 1ULL) == 1ULL) {
2205
20
        ++maximum_quotient_bits;
2206
20
    }
2207
2208
20
    ASSERT(maximum_quotient_bits <= NUM_LIMB_BITS);
2209
20
    uint32_t quotient_limb_index = context->add_variable(bb::fr(quotient_value.lo));
2210
20
    field_t<Builder> quotient_limb = field_t<Builder>::from_witness_index(context, quotient_limb_index);
2211
20
    if constexpr (HasPlookup<Builder>) {
2212
20
        context->decompose_into_default_range(quotient_limb.get_normalized_witness_index(),
2213
20
                                              static_cast<size_t>(maximum_quotient_bits));
2214
20
    } else {
2215
20
        context->decompose_into_base4_accumulators(quotient_limb.get_normalized_witness_index(),
2216
20
                                                   static_cast<size_t>(maximum_quotient_bits),
2217
20
                                                   "bigfield: quotient_limb too large.");
2218
20
    }
2219
2220
20
    ASSERT((uint1024_t(1) << maximum_quotient_bits) * uint1024_t(modulus_u512) + DEFAULT_MAXIMUM_REMAINDER <
2221
20
           get_maximum_crt_product());
2222
20
    quotient.binary_basis_limbs[0] = Limb(quotient_limb, uint256_t(1) << maximum_quotient_bits);
2223
20
    quotient.binary_basis_limbs[1] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2224
20
    quotient.binary_basis_limbs[2] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2225
20
    quotient.binary_basis_limbs[3] = Limb(field_t<Builder>::from_witness_index(context, context->zero_idx), 0);
2226
20
    quotient.prime_basis_limb = quotient_limb;
2227
    // this constructor with can_overflow=false will enforce remainder of size<2^s
2228
20
    bigfield remainder = bigfield(
2229
20
        witness_t(context, fr(remainder_value.slice(0, NUM_LIMB_BITS * 2).lo)),
2230
20
        witness_t(context, fr(remainder_value.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS).lo)));
2231
2232
20
    unsafe_evaluate_multiply_add(*this, one(), {}, quotient, { remainder });
2233
20
    binary_basis_limbs[0] =
2234
20
        remainder.binary_basis_limbs[0]; // Combination of const method and mutable variables is good practice?
2235
20
    binary_basis_limbs[1] = remainder.binary_basis_limbs[1];
2236
20
    binary_basis_limbs[2] = remainder.binary_basis_limbs[2];
2237
20
    binary_basis_limbs[3] = remainder.binary_basis_limbs[3];
2238
20
    prime_basis_limb = remainder.prime_basis_limb;
2239
20
    set_origin_tag(new_tag);
2240
20
} // namespace stdlib
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE11self_reduceEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE11self_reduceEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE11self_reduceEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE11self_reduceEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE11self_reduceEv
Unexecuted instantiation: _ZNK2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E11self_reduceEv
2241
2242
/**
2243
 * Evaluate a multiply add identity with several added elements and several remainders
2244
 *
2245
 * i.e:
2246
 *
2247
 * input_left*input_to_mul + (to_add[0]..to_add[-1]) - input_quotient*modulus -
2248
 * (input_remainders[0]+..+input_remainders[-1]) = 0 (mod CRT)
2249
 *
2250
 * See detailed explanation at https://hackmd.io/LoEG5nRHQe-PvstVaD51Yw?view
2251
 *
2252
 * THIS FUNCTION IS UNSAFE TO USE IN CIRCUITS AS IT DOES NOT PROTECT AGAINST CRT OVERFLOWS.
2253
 * */
2254
template <typename Builder, typename T>
2255
void bigfield<Builder, T>::unsafe_evaluate_multiply_add(const bigfield& input_left,
2256
                                                        const bigfield& input_to_mul,
2257
                                                        const std::vector<bigfield>& to_add,
2258
                                                        const bigfield& input_quotient,
2259
                                                        const std::vector<bigfield>& input_remainders)
2260
838k
{
2261
2262
838k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
838k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
0
    input_left.sanity_check();
2266
0
    input_to_mul.sanity_check();
2267
0
    input_quotient.sanity_check();
2268
1.03M
    for (auto& el : to_add) {
2269
1.03M
        el.sanity_check();
2270
1.03M
    }
2271
885k
    for (auto& el : input_remainders) {
2272
885k
        el.sanity_check();
2273
885k
    }
2274
2275
0
    std::vector<bigfield> remainders(input_remainders);
2276
2277
0
    bigfield left = input_left;
2278
0
    bigfield to_mul = input_to_mul;
2279
0
    bigfield quotient = input_quotient;
2280
2281
838k
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
0
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
0
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
0
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
0
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
0
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
0
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
0
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
0
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
0
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
0
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
0
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
0
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
0
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
0
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
0
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
0
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
0
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
0
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
0
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
0
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
0
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
0
    uint256_t borrow_lo_value = 0;
2308
885k
    for (const auto& remainder : input_remainders) {
2309
885k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
885k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
885k
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
885k
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
885k
    }
2315
0
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
0
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
0
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
0
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
0
    uint512_t max_a0(0);
2322
0
    uint512_t max_a1(0);
2323
1.87M
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
1.03M
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
1.03M
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
1.03M
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
1.03M
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
1.03M
    }
2329
0
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
0
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
0
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
0
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
0
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
838k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
212k
        ++max_lo_bits;
2337
212k
    }
2338
838k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
569k
        ++max_hi_bits;
2340
569k
    }
2341
2342
0
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
0
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
838k
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
838k
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
838k
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
838k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
16.0k
            bigfield output(input);
2356
16.0k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
16.0k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
16.0k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
16.0k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
16.0k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
16.0k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
16.0k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
16.0k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
16.0k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
16.0k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
16.0k
            output.context = ctx;
2367
16.0k
            return output;
2368
16.0k
        };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_ENKUlS8_E_clES8_
Line
Count
Source
2354
13.0k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
13.0k
            bigfield output(input);
2356
13.0k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
13.0k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
13.0k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
13.0k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
13.0k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
13.0k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
13.0k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
13.0k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
13.0k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
13.0k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
13.0k
            output.context = ctx;
2367
13.0k
            return output;
2368
13.0k
        };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_ENKUlS8_E_clES8_
Line
Count
Source
2354
700
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
700
            bigfield output(input);
2356
700
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
700
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
700
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
700
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
700
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
700
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
700
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
700
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
700
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
700
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
700
            output.context = ctx;
2367
700
            return output;
2368
700
        };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS8_SA_RKSt6vectorIS8_SaIS8_EESA_SF_ENKUlSA_E_clESA_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ENKUlS9_E_clES9_
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ENKUlS9_E_clES9_
Line
Count
Source
2354
70
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
70
            bigfield output(input);
2356
70
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
70
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
70
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
70
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
70
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
70
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
70
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
70
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
70
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
70
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
70
            output.context = ctx;
2367
70
            return output;
2368
70
        };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ENKUlS9_E_clES9_
Line
Count
Source
2354
48
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
48
            bigfield output(input);
2356
48
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
48
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
48
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
48
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
48
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
48
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
48
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
48
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
48
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
48
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
48
            output.context = ctx;
2367
48
            return output;
2368
48
        };
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_ENKUlSB_E_clESB_
Line
Count
Source
2354
1.29k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
1.29k
            bigfield output(input);
2356
1.29k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
1.29k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
1.29k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
1.29k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
1.29k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
1.29k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
1.29k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
1.29k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
1.29k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
1.29k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
1.29k
            output.context = ctx;
2367
1.29k
            return output;
2368
1.29k
        };
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_ENKUlSB_E_clESB_
Line
Count
Source
2354
864
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
864
            bigfield output(input);
2356
864
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
864
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
864
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
864
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
864
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
864
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
864
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
864
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
864
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
864
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
864
            output.context = ctx;
2367
864
            return output;
2368
864
        };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ENKUlS9_E_clES9_
Line
Count
Source
2354
23
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
23
            bigfield output(input);
2356
23
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
23
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
23
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
23
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
23
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
23
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
23
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
23
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
23
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
23
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
23
            output.context = ctx;
2367
23
            return output;
2368
23
        };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_ENKUlS9_E_clES9_
Line
Count
Source
2354
40
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
40
            bigfield output(input);
2356
40
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
40
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
40
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
40
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
40
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
40
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
40
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
40
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
40
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
40
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
40
            output.context = ctx;
2367
40
            return output;
2368
40
        };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_ENKUlSB_E_clESB_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_ENKUlSB_E_clESB_
2369
838k
        if (left.is_constant()) {
2370
6.16k
            left = convert_constant_to_fixed_witness(left);
2371
6.16k
        }
2372
838k
        if (to_mul.is_constant()) {
2373
4.61k
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
4.61k
        }
2375
838k
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
838k
        if (remainders[0].is_constant()) {
2379
5.31k
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
5.31k
        }
2381
2382
838k
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
838k
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
838k
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
885k
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
47.2k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
47.2k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
47.2k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
47.2k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
47.2k
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
47.2k
        }
2392
1.03M
        for (const auto& add : to_add) {
2393
1.03M
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
1.03M
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
1.03M
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
1.03M
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
1.03M
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
1.03M
        }
2399
2400
838k
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
838k
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
838k
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
838k
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
838k
        if (needs_normalize) {
2406
42.3k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
42.3k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
42.3k
        }
2409
2410
838k
        field_t<Builder> remainder_limbs[4]{
2411
838k
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
838k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
838k
                            : remainders[0].binary_basis_limbs[1].element,
2414
838k
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
838k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
838k
                            : remainders[0].binary_basis_limbs[3].element,
2417
838k
        };
2418
838k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
838k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
838k
            {
2422
838k
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
838k
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
838k
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
838k
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
838k
            },
2427
838k
            {
2428
838k
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
838k
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
838k
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
838k
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
838k
            },
2433
838k
            {
2434
838k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
838k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
838k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
838k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
838k
            },
2439
838k
            {
2440
838k
                remainder_limbs[0].get_normalized_witness_index(),
2441
838k
                remainder_limbs[1].get_normalized_witness_index(),
2442
838k
                remainder_limbs[2].get_normalized_witness_index(),
2443
838k
                remainder_limbs[3].get_normalized_witness_index(),
2444
838k
            },
2445
838k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
838k
            modulus,
2447
838k
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
838k
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
838k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
838k
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
838k
                                                       to_mul.prime_basis_limb,
2454
838k
                                                       quotient.prime_basis_limb * neg_prime,
2455
838k
                                                       -remainder_prime_limb);
2456
2457
838k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
838k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
838k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
34.5k
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
34.5k
                                           lo.get_normalized_witness_index(),
2465
34.5k
                                           size_t(carry_hi_msb),
2466
34.5k
                                           size_t(carry_lo_msb));
2467
803k
        } else {
2468
803k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
803k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
803k
        }
2471
838k
    } else {
2472
0
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
0
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
0
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
0
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
0
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
0
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
0
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
0
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
0
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
0
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
0
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
0
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
0
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
0
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
0
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
0
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
0
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
0
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
0
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
0
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
0
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
0
        const field_t r2 = c0.add_two(c1, c2);
2503
0
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
0
        field_t carry_lo_0 = r0 * shift_right_2;
2506
0
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
0
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
0
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
0
        for (const auto& add_element : to_add) {
2510
0
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
0
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
0
        }
2513
0
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
0
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
0
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
0
        }
2517
0
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
0
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
0
        carry_lo += borrow_lo;
2520
0
        field_t carry_hi_0 = r2 * shift_right_2;
2521
0
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
0
        field_t carry_hi_2 = t1 * shift_right_2;
2523
0
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
0
        for (const auto& add_element : to_add) {
2526
0
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
0
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
0
        }
2529
0
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
0
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
0
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
0
        }
2533
0
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
0
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
0
        if (to_add.size() >= 2) {
2537
0
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
0
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
0
            }
2540
0
        }
2541
0
        if ((to_add.size() & 1UL) == 1UL) {
2542
0
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
0
        }
2544
0
        if (remainders.size() >= 2) {
2545
0
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
0
                linear_terms =
2547
0
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
0
            }
2549
0
        }
2550
0
        if ((remainders.size() & 1UL) == 1UL) {
2551
0
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
0
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
0
        field_t<Builder>::evaluate_polynomial_identity(
2555
0
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
0
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
0
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
0
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
0
            carry_combined = carry_combined.normalize();
2561
0
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
0
                carry_combined.get_normalized_witness_index(),
2563
0
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
0
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
0
            field_t<Builder> accumulator_midpoint =
2566
0
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
0
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
0
        } else {
2569
0
            carry_lo = carry_lo.normalize();
2570
0
            carry_hi = carry_hi.normalize();
2571
0
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
0
                                                   static_cast<size_t>(carry_lo_msb),
2573
0
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
0
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
0
                                                   static_cast<size_t>(carry_hi_msb),
2576
0
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
0
        }
2578
0
    }
2579
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_
Line
Count
Source
2260
772k
{
2261
2262
772k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
772k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
772k
    input_left.sanity_check();
2266
772k
    input_to_mul.sanity_check();
2267
772k
    input_quotient.sanity_check();
2268
947k
    for (auto& el : to_add) {
2269
947k
        el.sanity_check();
2270
947k
    }
2271
819k
    for (auto& el : input_remainders) {
2272
819k
        el.sanity_check();
2273
819k
    }
2274
2275
772k
    std::vector<bigfield> remainders(input_remainders);
2276
2277
772k
    bigfield left = input_left;
2278
772k
    bigfield to_mul = input_to_mul;
2279
772k
    bigfield quotient = input_quotient;
2280
2281
772k
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
772k
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
772k
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
772k
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
772k
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
772k
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
772k
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
772k
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
772k
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
772k
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
772k
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
772k
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
772k
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
772k
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
772k
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
772k
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
772k
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
772k
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
772k
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
772k
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
772k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
772k
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
772k
    uint256_t borrow_lo_value = 0;
2308
819k
    for (const auto& remainder : input_remainders) {
2309
819k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
819k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
819k
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
819k
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
819k
    }
2315
772k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
772k
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
772k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
772k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
772k
    uint512_t max_a0(0);
2322
772k
    uint512_t max_a1(0);
2323
1.71M
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
947k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
947k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
947k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
947k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
947k
    }
2329
772k
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
772k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
772k
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
772k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
772k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
772k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
184k
        ++max_lo_bits;
2337
184k
    }
2338
772k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
566k
        ++max_hi_bits;
2340
566k
    }
2341
2342
772k
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
772k
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
772k
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
772k
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
772k
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
772k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
772k
            bigfield output(input);
2356
772k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
772k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
772k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
772k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
772k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
772k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
772k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
772k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
772k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
772k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
772k
            output.context = ctx;
2367
772k
            return output;
2368
772k
        };
2369
772k
        if (left.is_constant()) {
2370
6.16k
            left = convert_constant_to_fixed_witness(left);
2371
6.16k
        }
2372
772k
        if (to_mul.is_constant()) {
2373
1.91k
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
1.91k
        }
2375
772k
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
772k
        if (remainders[0].is_constant()) {
2379
4.97k
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
4.97k
        }
2381
2382
772k
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
772k
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
772k
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
819k
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
47.0k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
47.0k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
47.0k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
47.0k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
47.0k
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
47.0k
        }
2392
947k
        for (const auto& add : to_add) {
2393
947k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
947k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
947k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
947k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
947k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
947k
        }
2399
2400
772k
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
772k
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
772k
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
772k
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
772k
        if (needs_normalize) {
2406
37.0k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
37.0k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
37.0k
        }
2409
2410
772k
        field_t<Builder> remainder_limbs[4]{
2411
772k
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
772k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
772k
                            : remainders[0].binary_basis_limbs[1].element,
2414
772k
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
772k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
772k
                            : remainders[0].binary_basis_limbs[3].element,
2417
772k
        };
2418
772k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
772k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
772k
            {
2422
772k
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
772k
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
772k
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
772k
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
772k
            },
2427
772k
            {
2428
772k
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
772k
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
772k
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
772k
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
772k
            },
2433
772k
            {
2434
772k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
772k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
772k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
772k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
772k
            },
2439
772k
            {
2440
772k
                remainder_limbs[0].get_normalized_witness_index(),
2441
772k
                remainder_limbs[1].get_normalized_witness_index(),
2442
772k
                remainder_limbs[2].get_normalized_witness_index(),
2443
772k
                remainder_limbs[3].get_normalized_witness_index(),
2444
772k
            },
2445
772k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
772k
            modulus,
2447
772k
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
772k
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
772k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
772k
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
772k
                                                       to_mul.prime_basis_limb,
2454
772k
                                                       quotient.prime_basis_limb * neg_prime,
2455
772k
                                                       -remainder_prime_limb);
2456
2457
772k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
772k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
772k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
8.33k
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
8.33k
                                           lo.get_normalized_witness_index(),
2465
8.33k
                                           size_t(carry_hi_msb),
2466
8.33k
                                           size_t(carry_lo_msb));
2467
763k
        } else {
2468
763k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
763k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
763k
        }
2471
772k
    } else {
2472
772k
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
772k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
772k
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
772k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
772k
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
772k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
772k
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
772k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
772k
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
772k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
772k
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
772k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
772k
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
772k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
772k
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
772k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
772k
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
772k
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
772k
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
772k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
772k
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
772k
        const field_t r2 = c0.add_two(c1, c2);
2503
772k
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
772k
        field_t carry_lo_0 = r0 * shift_right_2;
2506
772k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
772k
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
772k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
772k
        for (const auto& add_element : to_add) {
2510
772k
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
772k
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
772k
        }
2513
772k
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
772k
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
772k
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
772k
        }
2517
772k
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
772k
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
772k
        carry_lo += borrow_lo;
2520
772k
        field_t carry_hi_0 = r2 * shift_right_2;
2521
772k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
772k
        field_t carry_hi_2 = t1 * shift_right_2;
2523
772k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
772k
        for (const auto& add_element : to_add) {
2526
772k
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
772k
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
772k
        }
2529
772k
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
772k
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
772k
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
772k
        }
2533
772k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
772k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
772k
        if (to_add.size() >= 2) {
2537
772k
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
772k
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
772k
            }
2540
772k
        }
2541
772k
        if ((to_add.size() & 1UL) == 1UL) {
2542
772k
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
772k
        }
2544
772k
        if (remainders.size() >= 2) {
2545
772k
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
772k
                linear_terms =
2547
772k
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
772k
            }
2549
772k
        }
2550
772k
        if ((remainders.size() & 1UL) == 1UL) {
2551
772k
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
772k
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
772k
        field_t<Builder>::evaluate_polynomial_identity(
2555
772k
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
772k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
772k
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
772k
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
772k
            carry_combined = carry_combined.normalize();
2561
772k
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
772k
                carry_combined.get_normalized_witness_index(),
2563
772k
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
772k
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
772k
            field_t<Builder> accumulator_midpoint =
2566
772k
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
772k
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
772k
        } else {
2569
772k
            carry_lo = carry_lo.normalize();
2570
772k
            carry_hi = carry_hi.normalize();
2571
772k
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
772k
                                                   static_cast<size_t>(carry_lo_msb),
2573
772k
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
772k
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
772k
                                                   static_cast<size_t>(carry_hi_msb),
2576
772k
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
772k
        }
2578
772k
    }
2579
772k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_
Line
Count
Source
2260
378
{
2261
2262
378
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
378
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
378
    input_left.sanity_check();
2266
378
    input_to_mul.sanity_check();
2267
378
    input_quotient.sanity_check();
2268
378
    for (auto& el : to_add) {
2269
0
        el.sanity_check();
2270
0
    }
2271
378
    for (auto& el : input_remainders) {
2272
378
        el.sanity_check();
2273
378
    }
2274
2275
378
    std::vector<bigfield> remainders(input_remainders);
2276
2277
378
    bigfield left = input_left;
2278
378
    bigfield to_mul = input_to_mul;
2279
378
    bigfield quotient = input_quotient;
2280
2281
378
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
378
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
378
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
378
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
378
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
378
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
378
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
378
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
378
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
378
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
378
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
378
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
378
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
378
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
378
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
378
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
378
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
378
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
378
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
378
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
378
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
378
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
378
    uint256_t borrow_lo_value = 0;
2308
378
    for (const auto& remainder : input_remainders) {
2309
378
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
378
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
378
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
378
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
378
    }
2315
378
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
378
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
378
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
378
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
378
    uint512_t max_a0(0);
2322
378
    uint512_t max_a1(0);
2323
378
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
0
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
0
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
0
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
0
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
0
    }
2329
378
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
378
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
378
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
378
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
378
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
378
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
330
        ++max_lo_bits;
2337
330
    }
2338
378
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
8
        ++max_hi_bits;
2340
8
    }
2341
2342
378
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
378
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
378
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
378
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
378
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
378
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
378
            bigfield output(input);
2356
378
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
378
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
378
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
378
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
378
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
378
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
378
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
378
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
378
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
378
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
378
            output.context = ctx;
2367
378
            return output;
2368
378
        };
2369
378
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
378
        if (to_mul.is_constant()) {
2373
378
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
378
        }
2375
378
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
378
        if (remainders[0].is_constant()) {
2379
322
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
322
        }
2381
2382
378
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
378
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
378
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
378
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
0
        }
2392
378
        for (const auto& add : to_add) {
2393
0
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
0
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
0
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
0
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
0
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
0
        }
2399
2400
378
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
378
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
378
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
378
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
378
        if (needs_normalize) {
2406
0
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
0
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
0
        }
2409
2410
378
        field_t<Builder> remainder_limbs[4]{
2411
378
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
378
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
378
                            : remainders[0].binary_basis_limbs[1].element,
2414
378
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
378
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
378
                            : remainders[0].binary_basis_limbs[3].element,
2417
378
        };
2418
378
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
378
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
378
            {
2422
378
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
378
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
378
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
378
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
378
            },
2427
378
            {
2428
378
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
378
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
378
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
378
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
378
            },
2433
378
            {
2434
378
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
378
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
378
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
378
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
378
            },
2439
378
            {
2440
378
                remainder_limbs[0].get_normalized_witness_index(),
2441
378
                remainder_limbs[1].get_normalized_witness_index(),
2442
378
                remainder_limbs[2].get_normalized_witness_index(),
2443
378
                remainder_limbs[3].get_normalized_witness_index(),
2444
378
            },
2445
378
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
378
            modulus,
2447
378
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
378
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
378
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
378
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
378
                                                       to_mul.prime_basis_limb,
2454
378
                                                       quotient.prime_basis_limb * neg_prime,
2455
378
                                                       -remainder_prime_limb);
2456
2457
378
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
378
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
378
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
370
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
370
                                           lo.get_normalized_witness_index(),
2465
370
                                           size_t(carry_hi_msb),
2466
370
                                           size_t(carry_lo_msb));
2467
370
        } else {
2468
8
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
8
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
8
        }
2471
378
    } else {
2472
378
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
378
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
378
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
378
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
378
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
378
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
378
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
378
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
378
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
378
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
378
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
378
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
378
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
378
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
378
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
378
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
378
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
378
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
378
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
378
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
378
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
378
        const field_t r2 = c0.add_two(c1, c2);
2503
378
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
378
        field_t carry_lo_0 = r0 * shift_right_2;
2506
378
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
378
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
378
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
378
        for (const auto& add_element : to_add) {
2510
378
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
378
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
378
        }
2513
378
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
378
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
378
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
378
        }
2517
378
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
378
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
378
        carry_lo += borrow_lo;
2520
378
        field_t carry_hi_0 = r2 * shift_right_2;
2521
378
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
378
        field_t carry_hi_2 = t1 * shift_right_2;
2523
378
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
378
        for (const auto& add_element : to_add) {
2526
378
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
378
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
378
        }
2529
378
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
378
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
378
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
378
        }
2533
378
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
378
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
378
        if (to_add.size() >= 2) {
2537
378
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
378
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
378
            }
2540
378
        }
2541
378
        if ((to_add.size() & 1UL) == 1UL) {
2542
378
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
378
        }
2544
378
        if (remainders.size() >= 2) {
2545
378
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
378
                linear_terms =
2547
378
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
378
            }
2549
378
        }
2550
378
        if ((remainders.size() & 1UL) == 1UL) {
2551
378
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
378
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
378
        field_t<Builder>::evaluate_polynomial_identity(
2555
378
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
378
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
378
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
378
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
378
            carry_combined = carry_combined.normalize();
2561
378
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
378
                carry_combined.get_normalized_witness_index(),
2563
378
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
378
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
378
            field_t<Builder> accumulator_midpoint =
2566
378
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
378
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
378
        } else {
2569
378
            carry_lo = carry_lo.normalize();
2570
378
            carry_hi = carry_hi.normalize();
2571
378
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
378
                                                   static_cast<size_t>(carry_lo_msb),
2573
378
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
378
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
378
                                                   static_cast<size_t>(carry_hi_msb),
2576
378
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
378
        }
2578
378
    }
2579
378
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS8_SA_RKSt6vectorIS8_SaIS8_EESA_SF_
Line
Count
Source
2260
16
{
2261
2262
16
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
16
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
16
    input_left.sanity_check();
2266
16
    input_to_mul.sanity_check();
2267
16
    input_quotient.sanity_check();
2268
16
    for (auto& el : to_add) {
2269
0
        el.sanity_check();
2270
0
    }
2271
16
    for (auto& el : input_remainders) {
2272
16
        el.sanity_check();
2273
16
    }
2274
2275
16
    std::vector<bigfield> remainders(input_remainders);
2276
2277
16
    bigfield left = input_left;
2278
16
    bigfield to_mul = input_to_mul;
2279
16
    bigfield quotient = input_quotient;
2280
2281
16
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
16
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
16
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
16
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
16
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
16
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
16
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
16
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
16
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
16
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
16
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
16
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
16
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
16
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
16
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
16
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
16
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
16
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
16
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
16
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
16
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
16
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
16
    uint256_t borrow_lo_value = 0;
2308
16
    for (const auto& remainder : input_remainders) {
2309
16
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
16
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
16
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
16
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
16
    }
2315
16
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
16
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
16
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
16
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
16
    uint512_t max_a0(0);
2322
16
    uint512_t max_a1(0);
2323
16
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
0
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
0
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
0
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
0
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
0
    }
2329
16
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
16
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
16
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
16
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
16
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
16
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
0
        ++max_lo_bits;
2337
0
    }
2338
16
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
16
        ++max_hi_bits;
2340
16
    }
2341
2342
16
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
16
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
16
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
16
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
16
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
16
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
16
            bigfield output(input);
2356
16
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
16
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
16
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
16
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
16
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
16
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
16
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
16
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
16
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
16
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
16
            output.context = ctx;
2367
16
            return output;
2368
16
        };
2369
16
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
16
        if (to_mul.is_constant()) {
2373
0
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
0
        }
2375
16
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
16
        if (remainders[0].is_constant()) {
2379
0
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
0
        }
2381
2382
16
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
16
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
16
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
16
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
0
        }
2392
16
        for (const auto& add : to_add) {
2393
0
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
0
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
0
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
0
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
0
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
0
        }
2399
2400
16
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
16
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
16
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
16
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
16
        if (needs_normalize) {
2406
0
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
0
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
0
        }
2409
2410
16
        field_t<Builder> remainder_limbs[4]{
2411
16
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
16
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
16
                            : remainders[0].binary_basis_limbs[1].element,
2414
16
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
16
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
16
                            : remainders[0].binary_basis_limbs[3].element,
2417
16
        };
2418
16
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
16
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
16
            {
2422
16
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
16
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
16
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
16
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
16
            },
2427
16
            {
2428
16
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
16
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
16
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
16
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
16
            },
2433
16
            {
2434
16
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
16
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
16
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
16
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
16
            },
2439
16
            {
2440
16
                remainder_limbs[0].get_normalized_witness_index(),
2441
16
                remainder_limbs[1].get_normalized_witness_index(),
2442
16
                remainder_limbs[2].get_normalized_witness_index(),
2443
16
                remainder_limbs[3].get_normalized_witness_index(),
2444
16
            },
2445
16
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
16
            modulus,
2447
16
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
16
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
16
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
16
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
16
                                                       to_mul.prime_basis_limb,
2454
16
                                                       quotient.prime_basis_limb * neg_prime,
2455
16
                                                       -remainder_prime_limb);
2456
2457
16
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
16
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
16
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
0
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
0
                                           lo.get_normalized_witness_index(),
2465
0
                                           size_t(carry_hi_msb),
2466
0
                                           size_t(carry_lo_msb));
2467
16
        } else {
2468
16
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
16
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
16
        }
2471
16
    } else {
2472
16
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
16
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
16
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
16
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
16
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
16
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
16
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
16
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
16
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
16
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
16
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
16
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
16
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
16
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
16
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
16
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
16
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
16
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
16
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
16
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
16
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
16
        const field_t r2 = c0.add_two(c1, c2);
2503
16
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
16
        field_t carry_lo_0 = r0 * shift_right_2;
2506
16
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
16
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
16
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
16
        for (const auto& add_element : to_add) {
2510
16
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
16
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
16
        }
2513
16
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
16
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
16
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
16
        }
2517
16
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
16
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
16
        carry_lo += borrow_lo;
2520
16
        field_t carry_hi_0 = r2 * shift_right_2;
2521
16
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
16
        field_t carry_hi_2 = t1 * shift_right_2;
2523
16
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
16
        for (const auto& add_element : to_add) {
2526
16
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
16
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
16
        }
2529
16
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
16
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
16
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
16
        }
2533
16
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
16
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
16
        if (to_add.size() >= 2) {
2537
16
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
16
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
16
            }
2540
16
        }
2541
16
        if ((to_add.size() & 1UL) == 1UL) {
2542
16
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
16
        }
2544
16
        if (remainders.size() >= 2) {
2545
16
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
16
                linear_terms =
2547
16
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
16
            }
2549
16
        }
2550
16
        if ((remainders.size() & 1UL) == 1UL) {
2551
16
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
16
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
16
        field_t<Builder>::evaluate_polynomial_identity(
2555
16
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
16
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
16
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
16
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
16
            carry_combined = carry_combined.normalize();
2561
16
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
16
                carry_combined.get_normalized_witness_index(),
2563
16
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
16
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
16
            field_t<Builder> accumulator_midpoint =
2566
16
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
16
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
16
        } else {
2569
16
            carry_lo = carry_lo.normalize();
2570
16
            carry_hi = carry_hi.normalize();
2571
16
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
16
                                                   static_cast<size_t>(carry_lo_msb),
2573
16
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
16
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
16
                                                   static_cast<size_t>(carry_hi_msb),
2576
16
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
16
        }
2578
16
    }
2579
16
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_
Line
Count
Source
2260
2.74k
{
2261
2262
2.74k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
2.74k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
2.74k
    input_left.sanity_check();
2266
2.74k
    input_to_mul.sanity_check();
2267
2.74k
    input_quotient.sanity_check();
2268
3.73k
    for (auto& el : to_add) {
2269
3.73k
        el.sanity_check();
2270
3.73k
    }
2271
2.74k
    for (auto& el : input_remainders) {
2272
2.74k
        el.sanity_check();
2273
2.74k
    }
2274
2275
2.74k
    std::vector<bigfield> remainders(input_remainders);
2276
2277
2.74k
    bigfield left = input_left;
2278
2.74k
    bigfield to_mul = input_to_mul;
2279
2.74k
    bigfield quotient = input_quotient;
2280
2281
2.74k
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
2.74k
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
2.74k
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
2.74k
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
2.74k
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
2.74k
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
2.74k
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
2.74k
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
2.74k
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
2.74k
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
2.74k
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
2.74k
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
2.74k
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
2.74k
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
2.74k
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
2.74k
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
2.74k
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
2.74k
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
2.74k
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
2.74k
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
2.74k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
2.74k
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
2.74k
    uint256_t borrow_lo_value = 0;
2308
2.74k
    for (const auto& remainder : input_remainders) {
2309
2.74k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
2.74k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
2.74k
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
2.74k
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
2.74k
    }
2315
2.74k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
2.74k
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
2.74k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
2.74k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
2.74k
    uint512_t max_a0(0);
2322
2.74k
    uint512_t max_a1(0);
2323
6.47k
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
3.73k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
3.73k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
3.73k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
3.73k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
3.73k
    }
2329
2.74k
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
2.74k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
2.74k
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
2.74k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
2.74k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
2.74k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
1.22k
        ++max_lo_bits;
2337
1.22k
    }
2338
2.74k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
40
        ++max_hi_bits;
2340
40
    }
2341
2342
2.74k
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
2.74k
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
2.74k
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
2.74k
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
2.74k
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
2.74k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
2.74k
            bigfield output(input);
2356
2.74k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
2.74k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
2.74k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
2.74k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
2.74k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
2.74k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
2.74k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
2.74k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
2.74k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
2.74k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
2.74k
            output.context = ctx;
2367
2.74k
            return output;
2368
2.74k
        };
2369
2.74k
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
2.74k
        if (to_mul.is_constant()) {
2373
70
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
70
        }
2375
2.74k
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
2.74k
        if (remainders[0].is_constant()) {
2379
0
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
0
        }
2381
2382
2.74k
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
2.74k
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
2.74k
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
2.74k
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
6
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
6
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
6
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
6
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
6
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
6
        }
2392
3.73k
        for (const auto& add : to_add) {
2393
3.73k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
3.73k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
3.73k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
3.73k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
3.73k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
3.73k
        }
2399
2400
2.74k
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
2.74k
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
2.74k
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
2.74k
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
2.74k
        if (needs_normalize) {
2406
214
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
214
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
214
        }
2409
2410
2.74k
        field_t<Builder> remainder_limbs[4]{
2411
2.74k
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
2.74k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
2.74k
                            : remainders[0].binary_basis_limbs[1].element,
2414
2.74k
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
2.74k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
2.74k
                            : remainders[0].binary_basis_limbs[3].element,
2417
2.74k
        };
2418
2.74k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
2.74k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
2.74k
            {
2422
2.74k
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
2.74k
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
2.74k
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
2.74k
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
2.74k
            },
2427
2.74k
            {
2428
2.74k
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
2.74k
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
2.74k
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
2.74k
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
2.74k
            },
2433
2.74k
            {
2434
2.74k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
2.74k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
2.74k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
2.74k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
2.74k
            },
2439
2.74k
            {
2440
2.74k
                remainder_limbs[0].get_normalized_witness_index(),
2441
2.74k
                remainder_limbs[1].get_normalized_witness_index(),
2442
2.74k
                remainder_limbs[2].get_normalized_witness_index(),
2443
2.74k
                remainder_limbs[3].get_normalized_witness_index(),
2444
2.74k
            },
2445
2.74k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
2.74k
            modulus,
2447
2.74k
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
2.74k
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
2.74k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
2.74k
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
2.74k
                                                       to_mul.prime_basis_limb,
2454
2.74k
                                                       quotient.prime_basis_limb * neg_prime,
2455
2.74k
                                                       -remainder_prime_limb);
2456
2457
2.74k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
2.74k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
2.74k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
1.13k
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
1.13k
                                           lo.get_normalized_witness_index(),
2465
1.13k
                                           size_t(carry_hi_msb),
2466
1.13k
                                           size_t(carry_lo_msb));
2467
1.61k
        } else {
2468
1.61k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
1.61k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
1.61k
        }
2471
2.74k
    } else {
2472
2.74k
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
2.74k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
2.74k
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
2.74k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
2.74k
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
2.74k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
2.74k
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
2.74k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
2.74k
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
2.74k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
2.74k
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
2.74k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
2.74k
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
2.74k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
2.74k
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
2.74k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
2.74k
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
2.74k
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
2.74k
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
2.74k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
2.74k
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
2.74k
        const field_t r2 = c0.add_two(c1, c2);
2503
2.74k
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
2.74k
        field_t carry_lo_0 = r0 * shift_right_2;
2506
2.74k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
2.74k
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
2.74k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
2.74k
        for (const auto& add_element : to_add) {
2510
2.74k
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
2.74k
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
2.74k
        }
2513
2.74k
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
2.74k
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
2.74k
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
2.74k
        }
2517
2.74k
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
2.74k
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
2.74k
        carry_lo += borrow_lo;
2520
2.74k
        field_t carry_hi_0 = r2 * shift_right_2;
2521
2.74k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
2.74k
        field_t carry_hi_2 = t1 * shift_right_2;
2523
2.74k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
2.74k
        for (const auto& add_element : to_add) {
2526
2.74k
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
2.74k
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
2.74k
        }
2529
2.74k
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
2.74k
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
2.74k
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
2.74k
        }
2533
2.74k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
2.74k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
2.74k
        if (to_add.size() >= 2) {
2537
2.74k
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
2.74k
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
2.74k
            }
2540
2.74k
        }
2541
2.74k
        if ((to_add.size() & 1UL) == 1UL) {
2542
2.74k
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
2.74k
        }
2544
2.74k
        if (remainders.size() >= 2) {
2545
2.74k
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
2.74k
                linear_terms =
2547
2.74k
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
2.74k
            }
2549
2.74k
        }
2550
2.74k
        if ((remainders.size() & 1UL) == 1UL) {
2551
2.74k
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
2.74k
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
2.74k
        field_t<Builder>::evaluate_polynomial_identity(
2555
2.74k
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
2.74k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
2.74k
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
2.74k
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
2.74k
            carry_combined = carry_combined.normalize();
2561
2.74k
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
2.74k
                carry_combined.get_normalized_witness_index(),
2563
2.74k
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
2.74k
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
2.74k
            field_t<Builder> accumulator_midpoint =
2566
2.74k
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
2.74k
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
2.74k
        } else {
2569
2.74k
            carry_lo = carry_lo.normalize();
2570
2.74k
            carry_hi = carry_hi.normalize();
2571
2.74k
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
2.74k
                                                   static_cast<size_t>(carry_lo_msb),
2573
2.74k
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
2.74k
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
2.74k
                                                   static_cast<size_t>(carry_hi_msb),
2576
2.74k
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
2.74k
        }
2578
2.74k
    }
2579
2.74k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_
Line
Count
Source
2260
63
{
2261
2262
63
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
63
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
63
    input_left.sanity_check();
2266
63
    input_to_mul.sanity_check();
2267
63
    input_quotient.sanity_check();
2268
63
    for (auto& el : to_add) {
2269
26
        el.sanity_check();
2270
26
    }
2271
63
    for (auto& el : input_remainders) {
2272
63
        el.sanity_check();
2273
63
    }
2274
2275
63
    std::vector<bigfield> remainders(input_remainders);
2276
2277
63
    bigfield left = input_left;
2278
63
    bigfield to_mul = input_to_mul;
2279
63
    bigfield quotient = input_quotient;
2280
2281
63
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
63
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
63
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
63
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
63
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
63
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
63
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
63
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
63
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
63
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
63
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
63
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
63
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
63
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
63
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
63
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
63
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
63
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
63
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
63
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
63
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
63
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
63
    uint256_t borrow_lo_value = 0;
2308
63
    for (const auto& remainder : input_remainders) {
2309
63
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
63
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
63
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
63
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
63
    }
2315
63
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
63
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
63
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
63
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
63
    uint512_t max_a0(0);
2322
63
    uint512_t max_a1(0);
2323
89
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
26
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
26
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
26
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
26
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
26
    }
2329
63
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
63
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
63
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
63
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
63
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
63
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
3
        ++max_lo_bits;
2337
3
    }
2338
63
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
12
        ++max_hi_bits;
2340
12
    }
2341
2342
63
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
63
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
63
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
63
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
63
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
63
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
63
            bigfield output(input);
2356
63
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
63
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
63
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
63
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
63
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
63
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
63
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
63
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
63
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
63
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
63
            output.context = ctx;
2367
63
            return output;
2368
63
        };
2369
63
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
63
        if (to_mul.is_constant()) {
2373
48
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
48
        }
2375
63
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
63
        if (remainders[0].is_constant()) {
2379
0
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
0
        }
2381
2382
63
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
63
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
63
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
63
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
0
        }
2392
63
        for (const auto& add : to_add) {
2393
26
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
26
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
26
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
26
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
26
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
26
        }
2399
2400
63
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
63
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
63
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
63
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
63
        if (needs_normalize) {
2406
0
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
0
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
0
        }
2409
2410
63
        field_t<Builder> remainder_limbs[4]{
2411
63
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
63
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
63
                            : remainders[0].binary_basis_limbs[1].element,
2414
63
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
63
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
63
                            : remainders[0].binary_basis_limbs[3].element,
2417
63
        };
2418
63
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
63
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
63
            {
2422
63
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
63
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
63
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
63
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
63
            },
2427
63
            {
2428
63
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
63
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
63
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
63
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
63
            },
2433
63
            {
2434
63
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
63
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
63
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
63
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
63
            },
2439
63
            {
2440
63
                remainder_limbs[0].get_normalized_witness_index(),
2441
63
                remainder_limbs[1].get_normalized_witness_index(),
2442
63
                remainder_limbs[2].get_normalized_witness_index(),
2443
63
                remainder_limbs[3].get_normalized_witness_index(),
2444
63
            },
2445
63
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
63
            modulus,
2447
63
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
63
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
63
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
63
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
63
                                                       to_mul.prime_basis_limb,
2454
63
                                                       quotient.prime_basis_limb * neg_prime,
2455
63
                                                       -remainder_prime_limb);
2456
2457
63
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
63
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
63
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
50
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
50
                                           lo.get_normalized_witness_index(),
2465
50
                                           size_t(carry_hi_msb),
2466
50
                                           size_t(carry_lo_msb));
2467
50
        } else {
2468
13
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
13
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
13
        }
2471
63
    } else {
2472
63
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
63
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
63
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
63
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
63
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
63
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
63
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
63
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
63
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
63
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
63
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
63
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
63
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
63
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
63
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
63
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
63
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
63
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
63
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
63
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
63
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
63
        const field_t r2 = c0.add_two(c1, c2);
2503
63
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
63
        field_t carry_lo_0 = r0 * shift_right_2;
2506
63
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
63
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
63
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
63
        for (const auto& add_element : to_add) {
2510
63
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
63
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
63
        }
2513
63
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
63
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
63
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
63
        }
2517
63
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
63
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
63
        carry_lo += borrow_lo;
2520
63
        field_t carry_hi_0 = r2 * shift_right_2;
2521
63
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
63
        field_t carry_hi_2 = t1 * shift_right_2;
2523
63
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
63
        for (const auto& add_element : to_add) {
2526
63
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
63
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
63
        }
2529
63
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
63
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
63
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
63
        }
2533
63
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
63
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
63
        if (to_add.size() >= 2) {
2537
63
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
63
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
63
            }
2540
63
        }
2541
63
        if ((to_add.size() & 1UL) == 1UL) {
2542
63
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
63
        }
2544
63
        if (remainders.size() >= 2) {
2545
63
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
63
                linear_terms =
2547
63
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
63
            }
2549
63
        }
2550
63
        if ((remainders.size() & 1UL) == 1UL) {
2551
63
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
63
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
63
        field_t<Builder>::evaluate_polynomial_identity(
2555
63
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
63
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
63
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
63
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
63
            carry_combined = carry_combined.normalize();
2561
63
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
63
                carry_combined.get_normalized_witness_index(),
2563
63
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
63
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
63
            field_t<Builder> accumulator_midpoint =
2566
63
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
63
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
63
        } else {
2569
63
            carry_lo = carry_lo.normalize();
2570
63
            carry_hi = carry_hi.normalize();
2571
63
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
63
                                                   static_cast<size_t>(carry_lo_msb),
2573
63
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
63
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
63
                                                   static_cast<size_t>(carry_hi_msb),
2576
63
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
63
        }
2578
63
    }
2579
63
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_
Line
Count
Source
2260
58.1k
{
2261
2262
58.1k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
58.1k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
58.1k
    input_left.sanity_check();
2266
58.1k
    input_to_mul.sanity_check();
2267
58.1k
    input_quotient.sanity_check();
2268
81.5k
    for (auto& el : to_add) {
2269
81.5k
        el.sanity_check();
2270
81.5k
    }
2271
58.3k
    for (auto& el : input_remainders) {
2272
58.3k
        el.sanity_check();
2273
58.3k
    }
2274
2275
58.1k
    std::vector<bigfield> remainders(input_remainders);
2276
2277
58.1k
    bigfield left = input_left;
2278
58.1k
    bigfield to_mul = input_to_mul;
2279
58.1k
    bigfield quotient = input_quotient;
2280
2281
58.1k
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
58.1k
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
58.1k
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
58.1k
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
58.1k
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
58.1k
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
58.1k
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
58.1k
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
58.1k
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
58.1k
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
58.1k
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
58.1k
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
58.1k
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
58.1k
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
58.1k
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
58.1k
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
58.1k
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
58.1k
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
58.1k
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
58.1k
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
58.1k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
58.1k
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
58.1k
    uint256_t borrow_lo_value = 0;
2308
58.3k
    for (const auto& remainder : input_remainders) {
2309
58.3k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
58.3k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
58.3k
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
58.3k
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
58.3k
    }
2315
58.1k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
58.1k
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
58.1k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
58.1k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
58.1k
    uint512_t max_a0(0);
2322
58.1k
    uint512_t max_a1(0);
2323
139k
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
81.5k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
81.5k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
81.5k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
81.5k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
81.5k
    }
2329
58.1k
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
58.1k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
58.1k
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
58.1k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
58.1k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
58.1k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
25.7k
        ++max_lo_bits;
2337
25.7k
    }
2338
58.1k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
576
        ++max_hi_bits;
2340
576
    }
2341
2342
58.1k
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
58.1k
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
58.1k
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
58.1k
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
58.1k
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
58.1k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
58.1k
            bigfield output(input);
2356
58.1k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
58.1k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
58.1k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
58.1k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
58.1k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
58.1k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
58.1k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
58.1k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
58.1k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
58.1k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
58.1k
            output.context = ctx;
2367
58.1k
            return output;
2368
58.1k
        };
2369
58.1k
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
58.1k
        if (to_mul.is_constant()) {
2373
1.29k
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
1.29k
        }
2375
58.1k
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
58.1k
        if (remainders[0].is_constant()) {
2379
0
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
0
        }
2381
2382
58.1k
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
58.1k
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
58.1k
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
58.3k
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
144
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
144
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
144
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
144
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
144
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
144
        }
2392
81.5k
        for (const auto& add : to_add) {
2393
81.5k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
81.5k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
81.5k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
81.5k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
81.5k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
81.5k
        }
2399
2400
58.1k
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
58.1k
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
58.1k
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
58.1k
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
58.1k
        if (needs_normalize) {
2406
4.75k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
4.75k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
4.75k
        }
2409
2410
58.1k
        field_t<Builder> remainder_limbs[4]{
2411
58.1k
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
58.1k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
58.1k
                            : remainders[0].binary_basis_limbs[1].element,
2414
58.1k
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
58.1k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
58.1k
                            : remainders[0].binary_basis_limbs[3].element,
2417
58.1k
        };
2418
58.1k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
58.1k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
58.1k
            {
2422
58.1k
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
58.1k
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
58.1k
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
58.1k
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
58.1k
            },
2427
58.1k
            {
2428
58.1k
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
58.1k
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
58.1k
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
58.1k
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
58.1k
            },
2433
58.1k
            {
2434
58.1k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
58.1k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
58.1k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
58.1k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
58.1k
            },
2439
58.1k
            {
2440
58.1k
                remainder_limbs[0].get_normalized_witness_index(),
2441
58.1k
                remainder_limbs[1].get_normalized_witness_index(),
2442
58.1k
                remainder_limbs[2].get_normalized_witness_index(),
2443
58.1k
                remainder_limbs[3].get_normalized_witness_index(),
2444
58.1k
            },
2445
58.1k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
58.1k
            modulus,
2447
58.1k
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
58.1k
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
58.1k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
58.1k
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
58.1k
                                                       to_mul.prime_basis_limb,
2454
58.1k
                                                       quotient.prime_basis_limb * neg_prime,
2455
58.1k
                                                       -remainder_prime_limb);
2456
2457
58.1k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
58.1k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
58.1k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
23.7k
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
23.7k
                                           lo.get_normalized_witness_index(),
2465
23.7k
                                           size_t(carry_hi_msb),
2466
23.7k
                                           size_t(carry_lo_msb));
2467
34.4k
        } else {
2468
34.4k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
34.4k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
34.4k
        }
2471
58.1k
    } else {
2472
58.1k
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
58.1k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
58.1k
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
58.1k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
58.1k
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
58.1k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
58.1k
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
58.1k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
58.1k
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
58.1k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
58.1k
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
58.1k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
58.1k
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
58.1k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
58.1k
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
58.1k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
58.1k
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
58.1k
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
58.1k
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
58.1k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
58.1k
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
58.1k
        const field_t r2 = c0.add_two(c1, c2);
2503
58.1k
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
58.1k
        field_t carry_lo_0 = r0 * shift_right_2;
2506
58.1k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
58.1k
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
58.1k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
58.1k
        for (const auto& add_element : to_add) {
2510
58.1k
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
58.1k
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
58.1k
        }
2513
58.1k
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
58.1k
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
58.1k
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
58.1k
        }
2517
58.1k
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
58.1k
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
58.1k
        carry_lo += borrow_lo;
2520
58.1k
        field_t carry_hi_0 = r2 * shift_right_2;
2521
58.1k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
58.1k
        field_t carry_hi_2 = t1 * shift_right_2;
2523
58.1k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
58.1k
        for (const auto& add_element : to_add) {
2526
58.1k
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
58.1k
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
58.1k
        }
2529
58.1k
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
58.1k
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
58.1k
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
58.1k
        }
2533
58.1k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
58.1k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
58.1k
        if (to_add.size() >= 2) {
2537
58.1k
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
58.1k
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
58.1k
            }
2540
58.1k
        }
2541
58.1k
        if ((to_add.size() & 1UL) == 1UL) {
2542
58.1k
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
58.1k
        }
2544
58.1k
        if (remainders.size() >= 2) {
2545
58.1k
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
58.1k
                linear_terms =
2547
58.1k
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
58.1k
            }
2549
58.1k
        }
2550
58.1k
        if ((remainders.size() & 1UL) == 1UL) {
2551
58.1k
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
58.1k
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
58.1k
        field_t<Builder>::evaluate_polynomial_identity(
2555
58.1k
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
58.1k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
58.1k
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
58.1k
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
58.1k
            carry_combined = carry_combined.normalize();
2561
58.1k
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
58.1k
                carry_combined.get_normalized_witness_index(),
2563
58.1k
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
58.1k
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
58.1k
            field_t<Builder> accumulator_midpoint =
2566
58.1k
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
58.1k
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
58.1k
        } else {
2569
58.1k
            carry_lo = carry_lo.normalize();
2570
58.1k
            carry_hi = carry_hi.normalize();
2571
58.1k
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
58.1k
                                                   static_cast<size_t>(carry_lo_msb),
2573
58.1k
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
58.1k
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
58.1k
                                                   static_cast<size_t>(carry_hi_msb),
2576
58.1k
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
58.1k
        }
2578
58.1k
    }
2579
58.1k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_
Line
Count
Source
2260
1.15k
{
2261
2262
1.15k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
1.15k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
1.15k
    input_left.sanity_check();
2266
1.15k
    input_to_mul.sanity_check();
2267
1.15k
    input_quotient.sanity_check();
2268
1.15k
    for (auto& el : to_add) {
2269
576
        el.sanity_check();
2270
576
    }
2271
1.15k
    for (auto& el : input_remainders) {
2272
1.15k
        el.sanity_check();
2273
1.15k
    }
2274
2275
1.15k
    std::vector<bigfield> remainders(input_remainders);
2276
2277
1.15k
    bigfield left = input_left;
2278
1.15k
    bigfield to_mul = input_to_mul;
2279
1.15k
    bigfield quotient = input_quotient;
2280
2281
1.15k
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
1.15k
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
1.15k
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
1.15k
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
1.15k
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
1.15k
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
1.15k
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
1.15k
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
1.15k
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
1.15k
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
1.15k
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
1.15k
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
1.15k
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
1.15k
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
1.15k
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
1.15k
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
1.15k
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
1.15k
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
1.15k
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
1.15k
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
1.15k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
1.15k
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
1.15k
    uint256_t borrow_lo_value = 0;
2308
1.15k
    for (const auto& remainder : input_remainders) {
2309
1.15k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
1.15k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
1.15k
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
1.15k
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
1.15k
    }
2315
1.15k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
1.15k
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
1.15k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
1.15k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
1.15k
    uint512_t max_a0(0);
2322
1.15k
    uint512_t max_a1(0);
2323
1.72k
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
576
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
576
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
576
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
576
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
576
    }
2329
1.15k
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
1.15k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
1.15k
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
1.15k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
1.15k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
1.15k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
0
        ++max_lo_bits;
2337
0
    }
2338
1.15k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
288
        ++max_hi_bits;
2340
288
    }
2341
2342
1.15k
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
1.15k
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
1.15k
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
1.15k
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
1.15k
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
1.15k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
1.15k
            bigfield output(input);
2356
1.15k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
1.15k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
1.15k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
1.15k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
1.15k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
1.15k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
1.15k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
1.15k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
1.15k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
1.15k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
1.15k
            output.context = ctx;
2367
1.15k
            return output;
2368
1.15k
        };
2369
1.15k
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
1.15k
        if (to_mul.is_constant()) {
2373
864
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
864
        }
2375
1.15k
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
1.15k
        if (remainders[0].is_constant()) {
2379
0
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
0
        }
2381
2382
1.15k
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
1.15k
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
1.15k
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
1.15k
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
0
        }
2392
1.15k
        for (const auto& add : to_add) {
2393
576
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
576
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
576
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
576
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
576
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
576
        }
2399
2400
1.15k
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
1.15k
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
1.15k
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
1.15k
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
1.15k
        if (needs_normalize) {
2406
0
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
0
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
0
        }
2409
2410
1.15k
        field_t<Builder> remainder_limbs[4]{
2411
1.15k
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
1.15k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
1.15k
                            : remainders[0].binary_basis_limbs[1].element,
2414
1.15k
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
1.15k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
1.15k
                            : remainders[0].binary_basis_limbs[3].element,
2417
1.15k
        };
2418
1.15k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
1.15k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
1.15k
            {
2422
1.15k
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
1.15k
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
1.15k
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
1.15k
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
1.15k
            },
2427
1.15k
            {
2428
1.15k
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
1.15k
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
1.15k
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
1.15k
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
1.15k
            },
2433
1.15k
            {
2434
1.15k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
1.15k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
1.15k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
1.15k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
1.15k
            },
2439
1.15k
            {
2440
1.15k
                remainder_limbs[0].get_normalized_witness_index(),
2441
1.15k
                remainder_limbs[1].get_normalized_witness_index(),
2442
1.15k
                remainder_limbs[2].get_normalized_witness_index(),
2443
1.15k
                remainder_limbs[3].get_normalized_witness_index(),
2444
1.15k
            },
2445
1.15k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
1.15k
            modulus,
2447
1.15k
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
1.15k
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
1.15k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
1.15k
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
1.15k
                                                       to_mul.prime_basis_limb,
2454
1.15k
                                                       quotient.prime_basis_limb * neg_prime,
2455
1.15k
                                                       -remainder_prime_limb);
2456
2457
1.15k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
1.15k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
1.15k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
864
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
864
                                           lo.get_normalized_witness_index(),
2465
864
                                           size_t(carry_hi_msb),
2466
864
                                           size_t(carry_lo_msb));
2467
864
        } else {
2468
288
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
288
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
288
        }
2471
1.15k
    } else {
2472
1.15k
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
1.15k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
1.15k
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
1.15k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
1.15k
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
1.15k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
1.15k
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
1.15k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
1.15k
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
1.15k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
1.15k
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
1.15k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
1.15k
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
1.15k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
1.15k
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
1.15k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
1.15k
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
1.15k
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
1.15k
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
1.15k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
1.15k
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
1.15k
        const field_t r2 = c0.add_two(c1, c2);
2503
1.15k
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
1.15k
        field_t carry_lo_0 = r0 * shift_right_2;
2506
1.15k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
1.15k
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
1.15k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
1.15k
        for (const auto& add_element : to_add) {
2510
1.15k
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
1.15k
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
1.15k
        }
2513
1.15k
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
1.15k
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
1.15k
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
1.15k
        }
2517
1.15k
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
1.15k
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
1.15k
        carry_lo += borrow_lo;
2520
1.15k
        field_t carry_hi_0 = r2 * shift_right_2;
2521
1.15k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
1.15k
        field_t carry_hi_2 = t1 * shift_right_2;
2523
1.15k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
1.15k
        for (const auto& add_element : to_add) {
2526
1.15k
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
1.15k
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
1.15k
        }
2529
1.15k
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
1.15k
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
1.15k
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
1.15k
        }
2533
1.15k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
1.15k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
1.15k
        if (to_add.size() >= 2) {
2537
1.15k
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
1.15k
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
1.15k
            }
2540
1.15k
        }
2541
1.15k
        if ((to_add.size() & 1UL) == 1UL) {
2542
1.15k
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
1.15k
        }
2544
1.15k
        if (remainders.size() >= 2) {
2545
1.15k
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
1.15k
                linear_terms =
2547
1.15k
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
1.15k
            }
2549
1.15k
        }
2550
1.15k
        if ((remainders.size() & 1UL) == 1UL) {
2551
1.15k
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
1.15k
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
1.15k
        field_t<Builder>::evaluate_polynomial_identity(
2555
1.15k
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
1.15k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
1.15k
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
1.15k
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
1.15k
            carry_combined = carry_combined.normalize();
2561
1.15k
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
1.15k
                carry_combined.get_normalized_witness_index(),
2563
1.15k
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
1.15k
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
1.15k
            field_t<Builder> accumulator_midpoint =
2566
1.15k
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
1.15k
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
1.15k
        } else {
2569
1.15k
            carry_lo = carry_lo.normalize();
2570
1.15k
            carry_hi = carry_hi.normalize();
2571
1.15k
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
1.15k
                                                   static_cast<size_t>(carry_lo_msb),
2573
1.15k
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
1.15k
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
1.15k
                                                   static_cast<size_t>(carry_hi_msb),
2576
1.15k
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
1.15k
        }
2578
1.15k
    }
2579
1.15k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_
Line
Count
Source
2260
3.34k
{
2261
2262
3.34k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
3.34k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
3.34k
    input_left.sanity_check();
2266
3.34k
    input_to_mul.sanity_check();
2267
3.34k
    input_quotient.sanity_check();
2268
5.85k
    for (auto& el : to_add) {
2269
5.85k
        el.sanity_check();
2270
5.85k
    }
2271
3.35k
    for (auto& el : input_remainders) {
2272
3.35k
        el.sanity_check();
2273
3.35k
    }
2274
2275
3.34k
    std::vector<bigfield> remainders(input_remainders);
2276
2277
3.34k
    bigfield left = input_left;
2278
3.34k
    bigfield to_mul = input_to_mul;
2279
3.34k
    bigfield quotient = input_quotient;
2280
2281
3.34k
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
3.34k
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
3.34k
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
3.34k
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
3.34k
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
3.34k
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
3.34k
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
3.34k
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
3.34k
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
3.34k
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
3.34k
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
3.34k
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
3.34k
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
3.34k
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
3.34k
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
3.34k
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
3.34k
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
3.34k
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
3.34k
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
3.34k
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
3.34k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
3.34k
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
3.34k
    uint256_t borrow_lo_value = 0;
2308
3.35k
    for (const auto& remainder : input_remainders) {
2309
3.35k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
3.35k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
3.35k
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
3.35k
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
3.35k
    }
2315
3.34k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
3.34k
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
3.34k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
3.34k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
3.34k
    uint512_t max_a0(0);
2322
3.34k
    uint512_t max_a1(0);
2323
9.19k
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
5.85k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
5.85k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
5.85k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
5.85k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
5.85k
    }
2329
3.34k
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
3.34k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
3.34k
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
3.34k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
3.34k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
3.34k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
1.04k
        ++max_lo_bits;
2337
1.04k
    }
2338
3.34k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
1.66k
        ++max_hi_bits;
2340
1.66k
    }
2341
2342
3.34k
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
3.34k
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
3.34k
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
3.34k
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
3.34k
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
3.34k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
3.34k
            bigfield output(input);
2356
3.34k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
3.34k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
3.34k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
3.34k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
3.34k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
3.34k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
3.34k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
3.34k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
3.34k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
3.34k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
3.34k
            output.context = ctx;
2367
3.34k
            return output;
2368
3.34k
        };
2369
3.34k
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
3.34k
        if (to_mul.is_constant()) {
2373
13
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
13
        }
2375
3.34k
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
3.34k
        if (remainders[0].is_constant()) {
2379
10
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
10
        }
2381
2382
3.34k
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
3.34k
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
3.34k
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
3.35k
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
15
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
15
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
15
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
15
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
15
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
15
        }
2392
5.85k
        for (const auto& add : to_add) {
2393
5.85k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
5.85k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
5.85k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
5.85k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
5.85k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
5.85k
        }
2399
2400
3.34k
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
3.34k
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
3.34k
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
3.34k
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
3.34k
        if (needs_normalize) {
2406
320
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
320
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
320
        }
2409
2410
3.34k
        field_t<Builder> remainder_limbs[4]{
2411
3.34k
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
3.34k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
3.34k
                            : remainders[0].binary_basis_limbs[1].element,
2414
3.34k
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
3.34k
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
3.34k
                            : remainders[0].binary_basis_limbs[3].element,
2417
3.34k
        };
2418
3.34k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
3.34k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
3.34k
            {
2422
3.34k
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
3.34k
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
3.34k
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
3.34k
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
3.34k
            },
2427
3.34k
            {
2428
3.34k
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
3.34k
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
3.34k
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
3.34k
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
3.34k
            },
2433
3.34k
            {
2434
3.34k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
3.34k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
3.34k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
3.34k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
3.34k
            },
2439
3.34k
            {
2440
3.34k
                remainder_limbs[0].get_normalized_witness_index(),
2441
3.34k
                remainder_limbs[1].get_normalized_witness_index(),
2442
3.34k
                remainder_limbs[2].get_normalized_witness_index(),
2443
3.34k
                remainder_limbs[3].get_normalized_witness_index(),
2444
3.34k
            },
2445
3.34k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
3.34k
            modulus,
2447
3.34k
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
3.34k
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
3.34k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
3.34k
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
3.34k
                                                       to_mul.prime_basis_limb,
2454
3.34k
                                                       quotient.prime_basis_limb * neg_prime,
2455
3.34k
                                                       -remainder_prime_limb);
2456
2457
3.34k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
3.34k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
3.34k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
13
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
13
                                           lo.get_normalized_witness_index(),
2465
13
                                           size_t(carry_hi_msb),
2466
13
                                           size_t(carry_lo_msb));
2467
3.33k
        } else {
2468
3.33k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
3.33k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
3.33k
        }
2471
3.34k
    } else {
2472
3.34k
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
3.34k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
3.34k
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
3.34k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
3.34k
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
3.34k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
3.34k
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
3.34k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
3.34k
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
3.34k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
3.34k
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
3.34k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
3.34k
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
3.34k
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
3.34k
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
3.34k
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
3.34k
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
3.34k
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
3.34k
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
3.34k
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
3.34k
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
3.34k
        const field_t r2 = c0.add_two(c1, c2);
2503
3.34k
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
3.34k
        field_t carry_lo_0 = r0 * shift_right_2;
2506
3.34k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
3.34k
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
3.34k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
3.34k
        for (const auto& add_element : to_add) {
2510
3.34k
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
3.34k
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
3.34k
        }
2513
3.34k
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
3.34k
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
3.34k
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
3.34k
        }
2517
3.34k
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
3.34k
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
3.34k
        carry_lo += borrow_lo;
2520
3.34k
        field_t carry_hi_0 = r2 * shift_right_2;
2521
3.34k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
3.34k
        field_t carry_hi_2 = t1 * shift_right_2;
2523
3.34k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
3.34k
        for (const auto& add_element : to_add) {
2526
3.34k
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
3.34k
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
3.34k
        }
2529
3.34k
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
3.34k
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
3.34k
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
3.34k
        }
2533
3.34k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
3.34k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
3.34k
        if (to_add.size() >= 2) {
2537
3.34k
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
3.34k
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
3.34k
            }
2540
3.34k
        }
2541
3.34k
        if ((to_add.size() & 1UL) == 1UL) {
2542
3.34k
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
3.34k
        }
2544
3.34k
        if (remainders.size() >= 2) {
2545
3.34k
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
3.34k
                linear_terms =
2547
3.34k
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
3.34k
            }
2549
3.34k
        }
2550
3.34k
        if ((remainders.size() & 1UL) == 1UL) {
2551
3.34k
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
3.34k
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
3.34k
        field_t<Builder>::evaluate_polynomial_identity(
2555
3.34k
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
3.34k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
3.34k
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
3.34k
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
3.34k
            carry_combined = carry_combined.normalize();
2561
3.34k
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
3.34k
                carry_combined.get_normalized_witness_index(),
2563
3.34k
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
3.34k
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
3.34k
            field_t<Builder> accumulator_midpoint =
2566
3.34k
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
3.34k
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
3.34k
        } else {
2569
3.34k
            carry_lo = carry_lo.normalize();
2570
3.34k
            carry_hi = carry_hi.normalize();
2571
3.34k
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
3.34k
                                                   static_cast<size_t>(carry_lo_msb),
2573
3.34k
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
3.34k
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
3.34k
                                                   static_cast<size_t>(carry_hi_msb),
2576
3.34k
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
3.34k
        }
2578
3.34k
    }
2579
3.34k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_
Line
Count
Source
2260
40
{
2261
2262
40
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2263
40
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2264
    // Sanity checks
2265
40
    input_left.sanity_check();
2266
40
    input_to_mul.sanity_check();
2267
40
    input_quotient.sanity_check();
2268
40
    for (auto& el : to_add) {
2269
10
        el.sanity_check();
2270
10
    }
2271
40
    for (auto& el : input_remainders) {
2272
40
        el.sanity_check();
2273
40
    }
2274
2275
40
    std::vector<bigfield> remainders(input_remainders);
2276
2277
40
    bigfield left = input_left;
2278
40
    bigfield to_mul = input_to_mul;
2279
40
    bigfield quotient = input_quotient;
2280
2281
40
    Builder* ctx = left.context ? left.context : to_mul.context;
2282
2283
40
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2284
40
    max_b0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2285
40
    uint512_t max_b1 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2286
40
    max_b1 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2287
40
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2288
40
    max_c0 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2289
40
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2290
40
    max_c1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2291
40
    uint512_t max_c2 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2292
40
    max_c2 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2293
40
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * to_mul.binary_basis_limbs[0].maximum_value);
2294
40
    max_d0 += (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2295
40
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * to_mul.binary_basis_limbs[1].maximum_value);
2296
40
    max_d1 += (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2297
40
    uint512_t max_d2 = (left.binary_basis_limbs[1].maximum_value * to_mul.binary_basis_limbs[2].maximum_value);
2298
40
    max_d2 += (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2299
40
    uint512_t max_d3 = (left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[3].maximum_value);
2300
40
    max_d3 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2301
2302
40
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * to_mul.binary_basis_limbs[0].maximum_value;
2303
40
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2304
2305
40
    uint512_t max_r1 = max_b0 + max_b1;
2306
2307
40
    uint256_t borrow_lo_value = 0;
2308
40
    for (const auto& remainder : input_remainders) {
2309
40
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2310
40
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2311
2312
40
        borrow_lo_value += (remainder.binary_basis_limbs[0].maximum_value +
2313
40
                            (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS));
2314
40
    }
2315
40
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2316
40
    field_t borrow_lo(ctx, bb::fr(borrow_lo_value));
2317
2318
40
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2319
40
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2320
2321
40
    uint512_t max_a0(0);
2322
40
    uint512_t max_a1(0);
2323
50
    for (size_t i = 0; i < to_add.size(); ++i) {
2324
10
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2325
10
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2326
10
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2327
10
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2328
10
    }
2329
40
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
2330
40
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2331
40
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1 + max_lo_carry;
2332
2333
40
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2334
40
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2335
40
    if ((max_lo_bits & 1ULL) == 1ULL) {
2336
0
        ++max_lo_bits;
2337
0
    }
2338
40
    if ((max_hi_bits & 1ULL) == 1ULL) {
2339
10
        ++max_hi_bits;
2340
10
    }
2341
2342
40
    uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2343
40
    uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2344
2345
40
    if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2346
0
        carry_lo_msb = 0;
2347
0
    }
2348
40
    if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2349
0
        carry_hi_msb = 0;
2350
0
    }
2351
40
    if constexpr (HasPlookup<Builder>) {
2352
        // The plookup custom bigfield gate requires inputs are witnesses.
2353
        // If we're using constant values, instantiate them as circuit variables
2354
40
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2355
40
            bigfield output(input);
2356
40
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2357
40
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2358
40
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2359
40
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2360
40
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2361
40
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2362
40
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2363
40
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2364
40
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2365
40
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2366
40
            output.context = ctx;
2367
40
            return output;
2368
40
        };
2369
40
        if (left.is_constant()) {
2370
0
            left = convert_constant_to_fixed_witness(left);
2371
0
        }
2372
40
        if (to_mul.is_constant()) {
2373
30
            to_mul = convert_constant_to_fixed_witness(to_mul);
2374
30
        }
2375
40
        if (quotient.is_constant()) {
2376
0
            quotient = convert_constant_to_fixed_witness(quotient);
2377
0
        }
2378
40
        if (remainders[0].is_constant()) {
2379
10
            remainders[0] = convert_constant_to_fixed_witness(remainders[0]);
2380
10
        }
2381
2382
40
        std::vector<field_t<Builder>> limb_0_accumulator{ remainders[0].binary_basis_limbs[0].element };
2383
40
        std::vector<field_t<Builder>> limb_2_accumulator{ remainders[0].binary_basis_limbs[2].element };
2384
40
        std::vector<field_t<Builder>> prime_limb_accumulator{ remainders[0].prime_basis_limb };
2385
40
        for (size_t i = 1; i < remainders.size(); ++i) {
2386
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2387
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2388
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2389
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2390
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2391
0
        }
2392
40
        for (const auto& add : to_add) {
2393
10
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2394
10
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2395
10
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2396
10
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2397
10
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2398
10
        }
2399
2400
40
        const auto& t0 = remainders[0].binary_basis_limbs[1].element;
2401
40
        const auto& t1 = remainders[0].binary_basis_limbs[3].element;
2402
40
        bool needs_normalize = (t0.additive_constant != 0 || t0.multiplicative_constant != 1);
2403
40
        needs_normalize = needs_normalize || (t1.additive_constant != 0 || t1.multiplicative_constant != 1);
2404
2405
40
        if (needs_normalize) {
2406
0
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[1].element * shift_1);
2407
0
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[3].element * shift_1);
2408
0
        }
2409
2410
40
        field_t<Builder> remainder_limbs[4]{
2411
40
            field_t<Builder>::accumulate(limb_0_accumulator),
2412
40
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2413
40
                            : remainders[0].binary_basis_limbs[1].element,
2414
40
            field_t<Builder>::accumulate(limb_2_accumulator),
2415
40
            needs_normalize ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2416
40
                            : remainders[0].binary_basis_limbs[3].element,
2417
40
        };
2418
40
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2419
2420
40
        bb::non_native_field_witnesses<bb::fr> witnesses{
2421
40
            {
2422
40
                left.binary_basis_limbs[0].element.get_normalized_witness_index(),
2423
40
                left.binary_basis_limbs[1].element.get_normalized_witness_index(),
2424
40
                left.binary_basis_limbs[2].element.get_normalized_witness_index(),
2425
40
                left.binary_basis_limbs[3].element.get_normalized_witness_index(),
2426
40
            },
2427
40
            {
2428
40
                to_mul.binary_basis_limbs[0].element.get_normalized_witness_index(),
2429
40
                to_mul.binary_basis_limbs[1].element.get_normalized_witness_index(),
2430
40
                to_mul.binary_basis_limbs[2].element.get_normalized_witness_index(),
2431
40
                to_mul.binary_basis_limbs[3].element.get_normalized_witness_index(),
2432
40
            },
2433
40
            {
2434
40
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2435
40
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2436
40
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2437
40
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2438
40
            },
2439
40
            {
2440
40
                remainder_limbs[0].get_normalized_witness_index(),
2441
40
                remainder_limbs[1].get_normalized_witness_index(),
2442
40
                remainder_limbs[2].get_normalized_witness_index(),
2443
40
                remainder_limbs[3].get_normalized_witness_index(),
2444
40
            },
2445
40
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2446
40
            modulus,
2447
40
        };
2448
        // N.B. this method also evaluates the prime field component of the non-native field mul
2449
40
        const auto [lo_idx, hi_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2450
2451
40
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2452
40
        field_t<Builder>::evaluate_polynomial_identity(left.prime_basis_limb,
2453
40
                                                       to_mul.prime_basis_limb,
2454
40
                                                       quotient.prime_basis_limb * neg_prime,
2455
40
                                                       -remainder_prime_limb);
2456
2457
40
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_idx) + borrow_lo;
2458
40
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_idx);
2459
2460
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2461
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2462
40
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2463
30
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2464
30
                                           lo.get_normalized_witness_index(),
2465
30
                                           size_t(carry_hi_msb),
2466
30
                                           size_t(carry_lo_msb));
2467
30
        } else {
2468
10
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2469
10
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2470
10
        }
2471
40
    } else {
2472
40
        const field_t b0 = left.binary_basis_limbs[1].element.madd(
2473
40
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2474
40
        const field_t b1 = left.binary_basis_limbs[0].element.madd(
2475
40
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2476
40
        const field_t c0 = left.binary_basis_limbs[1].element.madd(
2477
40
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2478
40
        const field_t c1 = left.binary_basis_limbs[2].element.madd(
2479
40
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2480
40
        const field_t c2 = left.binary_basis_limbs[0].element.madd(
2481
40
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2482
40
        const field_t d0 = left.binary_basis_limbs[3].element.madd(
2483
40
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2484
40
        const field_t d1 = left.binary_basis_limbs[2].element.madd(
2485
40
            to_mul.binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2486
40
        const field_t d2 = left.binary_basis_limbs[1].element.madd(
2487
40
            to_mul.binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2488
40
        const field_t d3 = left.binary_basis_limbs[0].element.madd(
2489
40
            to_mul.binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2490
2491
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
2492
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
2493
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
2494
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
2495
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
2496
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
2497
2498
40
        const field_t r0 = left.binary_basis_limbs[0].element.madd(
2499
40
            to_mul.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
2500
2501
40
        field_t r1 = b0.add_two(b1, -remainders[0].binary_basis_limbs[1].element);
2502
40
        const field_t r2 = c0.add_two(c1, c2);
2503
40
        const field_t r3 = d0 + d1.add_two(d2, d3);
2504
2505
40
        field_t carry_lo_0 = r0 * shift_right_2;
2506
40
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
2507
40
        field_t carry_lo_2 = -(remainders[0].binary_basis_limbs[0].element * shift_right_2);
2508
40
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
2509
40
        for (const auto& add_element : to_add) {
2510
40
            carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
2511
40
                                        add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2512
40
        }
2513
40
        for (size_t i = 1; i < remainders.size(); ++i) {
2514
40
            carry_lo = carry_lo.add_two(-remainders[i].binary_basis_limbs[0].element * shift_right_2,
2515
40
                                        -remainders[i].binary_basis_limbs[1].element * (shift_1 * shift_right_2));
2516
40
        }
2517
40
        field_t t1 = carry_lo.add_two(-remainders[0].binary_basis_limbs[2].element,
2518
40
                                      -(remainders[0].binary_basis_limbs[3].element * shift_1));
2519
40
        carry_lo += borrow_lo;
2520
40
        field_t carry_hi_0 = r2 * shift_right_2;
2521
40
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
2522
40
        field_t carry_hi_2 = t1 * shift_right_2;
2523
40
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
2524
2525
40
        for (const auto& add_element : to_add) {
2526
40
            carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
2527
40
                                        add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2528
40
        }
2529
40
        for (size_t i = 1; i < remainders.size(); ++i) {
2530
40
            carry_hi = carry_hi.add_two(-remainders[i].binary_basis_limbs[2].element * shift_right_2,
2531
40
                                        -remainders[i].binary_basis_limbs[3].element * (shift_1 * shift_right_2));
2532
40
        }
2533
40
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2534
2535
40
        field_t<Builder> linear_terms(ctx, bb::fr(0));
2536
40
        if (to_add.size() >= 2) {
2537
40
            for (size_t i = 0; i < to_add.size(); i += 2) {
2538
40
                linear_terms = linear_terms.add_two(to_add[i].prime_basis_limb, to_add[i + 1].prime_basis_limb);
2539
40
            }
2540
40
        }
2541
40
        if ((to_add.size() & 1UL) == 1UL) {
2542
40
            linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
2543
40
        }
2544
40
        if (remainders.size() >= 2) {
2545
40
            for (size_t i = 0; i < (remainders.size() >> 1); i += 1) {
2546
40
                linear_terms =
2547
40
                    linear_terms.add_two(-remainders[2 * i].prime_basis_limb, -remainders[2 * i + 1].prime_basis_limb);
2548
40
            }
2549
40
        }
2550
40
        if ((remainders.size() & 1UL) == 1UL) {
2551
40
            linear_terms += -remainders[remainders.size() - 1].prime_basis_limb;
2552
40
        }
2553
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
2554
40
        field_t<Builder>::evaluate_polynomial_identity(
2555
40
            left.prime_basis_limb, to_mul.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
2556
2557
40
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
2558
40
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
2559
40
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
2560
40
            carry_combined = carry_combined.normalize();
2561
40
            const auto accumulators = ctx->decompose_into_base4_accumulators(
2562
40
                carry_combined.get_normalized_witness_index(),
2563
40
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
2564
40
                "bigfield: carry_combined too large in unsafe_evaluate_multiply_add.");
2565
40
            field_t<Builder> accumulator_midpoint =
2566
40
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
2567
40
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
2568
40
        } else {
2569
40
            carry_lo = carry_lo.normalize();
2570
40
            carry_hi = carry_hi.normalize();
2571
40
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
2572
40
                                                   static_cast<size_t>(carry_lo_msb),
2573
40
                                                   "bigfield: carry_lo too large in unsafe_evaluate_multiply_add.");
2574
40
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
2575
40
                                                   static_cast<size_t>(carry_hi_msb),
2576
40
                                                   "bigfield: carry_hi too large in unsafe_evaluate_multiply_add.");
2577
40
        }
2578
40
    }
2579
40
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE28unsafe_evaluate_multiply_addERKS9_SB_RKSt6vectorIS9_SaIS9_EESB_SG_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE28unsafe_evaluate_multiply_addERKS6_S8_RKSt6vectorIS6_SaIS6_EES8_SD_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE28unsafe_evaluate_multiply_addERKS8_SA_RKSt6vectorIS8_SaIS8_EESA_SF_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E28unsafe_evaluate_multiply_addERKS7_S9_RKSt6vectorIS7_SaIS7_EES9_SE_
2580
/**
2581
 * Evaluate a quadratic relation involving multiple multiplications
2582
 *
2583
 * i.e. evalaute:
2584
 *
2585
 * (left_0 * right_0) + ... + (left_n-1 * right_n-1) + ...to_add - (input_quotient * q + ...input_remainders) = 0
2586
 *
2587
 * This method supports multiple "remainders" because, when evaluating divisions, some of these remainders are terms
2588
 * We're subtracting from our product (see msub_div for more details)
2589
 *
2590
 * The above quadratic relation can be evaluated using only a single quotient/remainder term.
2591
 *
2592
 * Params:
2593
 *
2594
 * `input_left`: left multiplication operands
2595
 * `input_right` : right multiplication operands
2596
 * `to_add` : vector of elements to add to the product
2597
 * `input_quotient` : quotient
2598
 * `input_remainders` : vector of remainders
2599
 *
2600
 * THIS METHOD IS UNSAFE TO USE IN CIRCUITS DIRECTLY AS IT LACKS OVERFLOW CHECKS.
2601
 **/
2602
template <typename Builder, typename T>
2603
void bigfield<Builder, T>::unsafe_evaluate_multiple_multiply_add(const std::vector<bigfield>& input_left,
2604
                                                                 const std::vector<bigfield>& input_right,
2605
                                                                 const std::vector<bigfield>& to_add,
2606
                                                                 const bigfield& input_quotient,
2607
                                                                 const std::vector<bigfield>& input_remainders)
2608
370k
{
2609
370k
    ASSERT(input_left.size() == input_right.size());
2610
370k
    ASSERT(input_left.size() <= MAXIMUM_SUMMAND_COUNT);
2611
370k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2612
370k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2613
2614
370k
    ASSERT(input_left.size() == input_right.size() && input_left.size() < 1024);
2615
    // Sanity checks
2616
824k
    for (auto& el : input_left) {
2617
824k
        el.sanity_check();
2618
824k
    }
2619
824k
    for (auto& el : input_right) {
2620
824k
        el.sanity_check();
2621
824k
    }
2622
653k
    for (auto& el : to_add) {
2623
653k
        el.sanity_check();
2624
653k
    }
2625
0
    input_quotient.sanity_check();
2626
370k
    for (auto& el : input_remainders) {
2627
370k
        el.sanity_check();
2628
370k
    }
2629
0
    std::vector<bigfield> remainders(input_remainders);
2630
0
    std::vector<bigfield> left(input_left);
2631
0
    std::vector<bigfield> right(input_right);
2632
0
    bigfield quotient = input_quotient;
2633
0
    const size_t num_multiplications = input_left.size();
2634
2635
370k
    Builder* ctx = input_left[0].context ? input_left[0].context : input_right[0].context;
2636
2637
824k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
824k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
824k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
824k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
824k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
824k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
824k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
824k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
824k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
824k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
824k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
824k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
824k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
824k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
824k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
824k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
824k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
824k
    };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_ENKUlSD_SD_E_clESD_SD_
Line
Count
Source
2637
743k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
743k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
743k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
743k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
743k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
743k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
743k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
743k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
743k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
743k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
743k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
743k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
743k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
743k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
743k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
743k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
743k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
743k
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_ENKUlSD_SD_E_clESD_SD_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS8_SaIS8_EESD_SD_RKS8_SD_ENKUlSF_SF_E_clESF_SF_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_SE_E_clESE_SE_
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_SE_E_clESE_SE_
Line
Count
Source
2637
3.15k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
3.15k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
3.15k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
3.15k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
3.15k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
3.15k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
3.15k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
3.15k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
3.15k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
3.15k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
3.15k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
3.15k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
3.15k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
3.15k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
3.15k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
3.15k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
3.15k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
3.15k
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_SE_E_clESE_SE_
_ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_SG_E_clESG_SG_
Line
Count
Source
2637
70.5k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
70.5k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
70.5k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
70.5k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
70.5k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
70.5k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
70.5k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
70.5k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
70.5k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
70.5k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
70.5k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
70.5k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
70.5k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
70.5k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
70.5k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
70.5k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
70.5k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
70.5k
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_SG_E_clESG_SG_
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_SE_E_clESE_SE_
Line
Count
Source
2637
7.01k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
7.01k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
7.01k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
7.01k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
7.01k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
7.01k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
7.01k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
7.01k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
7.01k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
7.01k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
7.01k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
7.01k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
7.01k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
7.01k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
7.01k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
7.01k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
7.01k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
7.01k
    };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_SE_E_clESE_SE_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_SG_E_clESG_SG_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_SG_E_clESG_SG_
2656
2657
    /**
2658
     * Step 1: Compute the maximum potential value of our product limbs
2659
     *
2660
     * max_lo = maximum value of limb products that span the range 0 - 2^{3t}
2661
     * max_hi = maximum value of limb products that span the range 2^{2t} - 2^{5t}
2662
     * (t = NUM_LIMB_BITS)
2663
     **/
2664
0
    uint512_t max_lo = 0;
2665
0
    uint512_t max_hi = 0;
2666
2667
    // Compute max values of quotient product limb products
2668
0
    uint512_t max_b0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2669
0
    uint512_t max_b1 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2670
0
    uint512_t max_c0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2671
0
    uint512_t max_c1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2672
0
    uint512_t max_c2 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2673
0
    uint512_t max_d0 = (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2674
0
    uint512_t max_d1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2675
0
    uint512_t max_d2 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2676
0
    uint512_t max_d3 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2677
2678
    // max_r0 = terms from 0 - 2^2t
2679
    // max_r1 = terms from 2^t - 2^3t
2680
    // max_r2 = terms from 2^2t - 2^4t
2681
    // max_r3 = terms from 2^3t - 2^5t
2682
0
    uint512_t max_r0 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2683
0
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2684
0
    uint512_t max_r1 = max_b0 + max_b1;
2685
2686
0
    uint256_t borrow_lo_value(0);
2687
370k
    for (const auto& remainder : input_remainders) {
2688
370k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2689
370k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2690
2691
370k
        borrow_lo_value += remainder.binary_basis_limbs[0].maximum_value +
2692
370k
                           (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2693
370k
    }
2694
0
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2695
0
    field_t<Builder> borrow_lo(ctx, bb::fr(borrow_lo_value));
2696
2697
0
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2698
0
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2699
2700
    // update max_lo, max_hi with quotient limb product terms.
2701
0
    max_lo += max_r0 + (max_r1 << NUM_LIMB_BITS);
2702
0
    max_hi += max_r2 + (max_r3 << NUM_LIMB_BITS);
2703
2704
    // Compute maximum value of addition terms in `to_add` and add to max_lo, max_hi
2705
0
    uint512_t max_a0(0);
2706
0
    uint512_t max_a1(0);
2707
1.02M
    for (size_t i = 0; i < to_add.size(); ++i) {
2708
653k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2709
653k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2710
653k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2711
653k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2712
653k
    }
2713
0
    max_lo += max_a0;
2714
0
    max_hi += max_a1;
2715
2716
    // Compute the maximum value of our multiplication products and add to max_lo, max_hi
2717
1.19M
    for (size_t i = 0; i < num_multiplications; ++i) {
2718
824k
        const auto [product_lo, product_hi] = get_product_maximum(left[i], right[i]);
2719
824k
        max_lo += product_lo;
2720
824k
        max_hi += product_hi;
2721
824k
    }
2722
2723
0
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2724
0
    max_hi += max_lo_carry;
2725
    // Compute the maximum number of bits in `max_lo` and `max_hi` - this defines the range constraint values we
2726
    // will need to apply to validate our product
2727
0
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2728
0
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2729
    // Turbo range checks only work for even bit ranges, so make sure these values are even
2730
    // TODO: This neccessary anymore? Turbo range checks now work with odd bit ranges...
2731
370k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2732
78.9k
        ++max_lo_bits;
2733
78.9k
    }
2734
370k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2735
323k
        ++max_hi_bits;
2736
323k
    }
2737
2738
370k
    if constexpr (HasPlookup<Builder>) {
2739
        // The plookup custom bigfield gate requires inputs are witnesses.
2740
        // If we're using constant values, instantiate them as circuit variables
2741
2742
370k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2743
5
            bigfield output(input);
2744
5
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2745
5
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2746
5
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2747
5
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2748
5
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2749
5
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2750
5
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2751
5
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2752
5
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2753
5
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2754
5
            output.context = ctx;
2755
5
            return output;
2756
5
        };
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_ENKUlSD_E_clESD_
Line
Count
Source
2742
1
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2743
1
            bigfield output(input);
2744
1
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2745
1
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2746
1
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2747
1
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2748
1
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2749
1
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2750
1
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2751
1
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2752
1
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2753
1
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2754
1
            output.context = ctx;
2755
1
            return output;
2756
1
        };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_ENKUlSD_E_clESD_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS8_SaIS8_EESD_SD_RKS8_SD_ENKUlSF_E_clESF_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_E_clESE_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_E_clESE_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_E_clESE_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_E_clESG_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_E_clESG_
_ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_E_clESE_
Line
Count
Source
2742
4
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2743
4
            bigfield output(input);
2744
4
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2745
4
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2746
4
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2747
4
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2748
4
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2749
4
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2750
4
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2751
4
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2752
4
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2753
4
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2754
4
            output.context = ctx;
2755
4
            return output;
2756
4
        };
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_ENKUlSE_E_clESE_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_E_clESG_
Unexecuted instantiation: _ZZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_ENKUlSG_E_clESG_
2757
2758
        // evalaute a nnf mul and add into existing lohi output for our extra product terms
2759
        // we need to add the result of (left_b * right_b) into lo_1_idx and hi_1_idx
2760
        // our custom gate evaluates: ((a * b) + (q * neg_modulus) - r) / 2^{136} = lo + hi * 2^{136}
2761
        // where q is a 'quotient' bigfield and neg_modulus is defined by selector polynomial values
2762
        // The custom gate costs 7 constraints, which is cheaper than computing `a * b` using multiplication +
2763
        // addition gates But....we want to obtain `left_a * right_b + lo_1 + hi_1 * 2^{136} = lo + hi * 2^{136}` If
2764
        // we set `neg_modulus = [2^{136}, 0, 0, 0]` and `q = [lo_1, 0, hi_1, 0]`, then we will add `lo_1` into
2765
        // `lo`, and `lo_1/2^{136} + hi_1` into `hi`. we can then subtract off `lo_1/2^{136}` from `hi`, by setting
2766
        // `r = [0, 0, lo_1, 0]` This saves us 2 addition gates as we don't have to add together the outputs of two
2767
        // calls to `evaluate_non_native_field_multiplication`
2768
370k
        std::vector<field_t<Builder>> limb_0_accumulator;
2769
370k
        std::vector<field_t<Builder>> limb_2_accumulator;
2770
370k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2771
2772
1.19M
        for (size_t i = 0; i < num_multiplications; ++i) {
2773
824k
            if (i == 0 && left[0].is_constant()) {
2774
0
                left[0] = convert_constant_to_fixed_witness(left[0]);
2775
0
            }
2776
824k
            if (i == 0 && right[0].is_constant()) {
2777
1
                right[0] = convert_constant_to_fixed_witness(right[0]);
2778
1
            }
2779
824k
            if (i > 0 && left[i].is_constant()) {
2780
0
                left[i] = convert_constant_to_fixed_witness(left[i]);
2781
0
            }
2782
824k
            if (i > 0 && right[i].is_constant()) {
2783
4
                right[i] = convert_constant_to_fixed_witness(right[i]);
2784
4
            }
2785
2786
824k
            if (i > 0) {
2787
454k
                bb::non_native_field_witnesses<bb::fr> mul_witnesses = {
2788
454k
                    {
2789
454k
                        left[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2790
454k
                        left[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2791
454k
                        left[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2792
454k
                        left[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2793
454k
                    },
2794
454k
                    {
2795
454k
                        right[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2796
454k
                        right[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2797
454k
                        right[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2798
454k
                        right[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2799
454k
                    },
2800
454k
                    {
2801
454k
                        ctx->zero_idx,
2802
454k
                        ctx->zero_idx,
2803
454k
                        ctx->zero_idx,
2804
454k
                        ctx->zero_idx,
2805
454k
                    },
2806
454k
                    {
2807
454k
                        ctx->zero_idx,
2808
454k
                        ctx->zero_idx,
2809
454k
                        ctx->zero_idx,
2810
454k
                        ctx->zero_idx,
2811
454k
                    },
2812
454k
                    { 0, 0, 0, 0 },
2813
454k
                    modulus,
2814
454k
                };
2815
2816
454k
                const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses);
2817
2818
454k
                field_t<Builder> lo_2 = field_t<Builder>::from_witness_index(ctx, lo_2_idx);
2819
454k
                field_t<Builder> hi_2 = field_t<Builder>::from_witness_index(ctx, hi_2_idx);
2820
2821
454k
                limb_0_accumulator.emplace_back(-lo_2);
2822
454k
                limb_2_accumulator.emplace_back(-hi_2);
2823
454k
                prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
2824
454k
            }
2825
824k
        }
2826
370k
        if (quotient.is_constant()) {
2827
0
            quotient = convert_constant_to_fixed_witness(quotient);
2828
0
        }
2829
2830
370k
        bool no_remainders = remainders.size() == 0;
2831
370k
        if (!no_remainders) {
2832
370k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
2833
370k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
2834
370k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
2835
370k
        }
2836
370k
        for (size_t i = 1; i < remainders.size(); ++i) {
2837
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2838
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2839
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2840
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2841
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2842
0
        }
2843
653k
        for (const auto& add : to_add) {
2844
653k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2845
653k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2846
653k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2847
653k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2848
653k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2849
653k
        }
2850
2851
370k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
2852
370k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
2853
370k
        if (accumulated_lo.is_constant()) {
2854
0
            accumulated_lo =
2855
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
2856
0
        }
2857
370k
        if (accumulated_hi.is_constant()) {
2858
0
            accumulated_hi =
2859
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
2860
0
        }
2861
370k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2862
370k
                                                    : remainders[0].binary_basis_limbs[1].element;
2863
370k
        if (remainder1.is_constant()) {
2864
0
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
2865
0
        }
2866
370k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2867
370k
                                                    : remainders[0].binary_basis_limbs[3].element;
2868
370k
        if (remainder3.is_constant()) {
2869
0
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
2870
0
        }
2871
370k
        field_t<Builder> remainder_limbs[4]{
2872
370k
            accumulated_lo,
2873
370k
            remainder1,
2874
370k
            accumulated_hi,
2875
370k
            remainder3,
2876
370k
        };
2877
370k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2878
2879
370k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2880
370k
            {
2881
370k
                left[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2882
370k
                left[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2883
370k
                left[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2884
370k
                left[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2885
370k
            },
2886
370k
            {
2887
370k
                right[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2888
370k
                right[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2889
370k
                right[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2890
370k
                right[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2891
370k
            },
2892
370k
            {
2893
370k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2894
370k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2895
370k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2896
370k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2897
370k
            },
2898
370k
            {
2899
370k
                remainder_limbs[0].get_normalized_witness_index(),
2900
370k
                remainder_limbs[1].get_normalized_witness_index(),
2901
370k
                remainder_limbs[2].get_normalized_witness_index(),
2902
370k
                remainder_limbs[3].get_normalized_witness_index(),
2903
370k
            },
2904
370k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2905
370k
            modulus,
2906
370k
        };
2907
2908
370k
        const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2909
2910
370k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2911
2912
370k
        field_t<Builder>::evaluate_polynomial_identity(left[0].prime_basis_limb,
2913
370k
                                                       right[0].prime_basis_limb,
2914
370k
                                                       quotient.prime_basis_limb * neg_prime,
2915
370k
                                                       -remainder_prime_limb);
2916
2917
370k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_1_idx) + borrow_lo;
2918
370k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_1_idx);
2919
2920
370k
        uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2921
370k
        uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2922
2923
370k
        if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2924
0
            carry_lo_msb = 0;
2925
0
        }
2926
370k
        if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2927
0
            carry_hi_msb = 0;
2928
0
        }
2929
2930
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2931
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2932
370k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2933
0
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2934
0
                                           lo.get_normalized_witness_index(),
2935
0
                                           (size_t)carry_hi_msb,
2936
0
                                           (size_t)carry_lo_msb);
2937
370k
        } else {
2938
370k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2939
370k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2940
370k
        }
2941
        /*  NOTE TO AUDITOR: An extraneous block
2942
               if constexpr (HasPlookup<Builder>) {
2943
                   carry_lo = carry_lo.normalize();
2944
                   carry_hi = carry_hi.normalize();
2945
                   ctx->decompose_into_default_range(carry_lo.witness_index, static_cast<size_t>(carry_lo_msb));
2946
                   ctx->decompose_into_default_range(carry_hi.witness_index, static_cast<size_t>(carry_hi_msb));
2947
               }
2948
            was removed from the `else` block below. See  the conversation at
2949
               https://github.com/AztecProtocol/aztec2-internal/pull/1023
2950
            We should make sure that no constraint like this is needed but missing (e.g., an equivalent constraint
2951
            was just imposed?). */
2952
370k
    } else {
2953
0
        field_t b0 = left[0].binary_basis_limbs[1].element.madd(
2954
0
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2955
0
        field_t b1 = left[0].binary_basis_limbs[0].element.madd(
2956
0
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2957
0
        field_t c0 = left[0].binary_basis_limbs[1].element.madd(
2958
0
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2959
0
        field_t c1 = left[0].binary_basis_limbs[2].element.madd(
2960
0
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2961
0
        field_t c2 = left[0].binary_basis_limbs[0].element.madd(
2962
0
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2963
0
        field_t d0 = left[0].binary_basis_limbs[3].element.madd(
2964
0
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2965
0
        field_t d1 = left[0].binary_basis_limbs[2].element.madd(
2966
0
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2967
0
        field_t d2 = left[0].binary_basis_limbs[1].element.madd(
2968
0
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2969
0
        field_t d3 = left[0].binary_basis_limbs[0].element.madd(
2970
0
            right[0].binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2971
2972
        /**
2973
         * Compute "limb accumulators"
2974
         * `limb_0_accumulator` contains contributions in the range 0 - 2^{3t}
2975
         * `limb_2_accumulator` contains contributiosn in the range 2^{2t} - 2^{5t} (t = MAX_NUM_LIMB_BITS)
2976
         * Actual range will vary a few bits because of lazy reduction techniques
2977
         *
2978
         * We store these values in an "accumulator" vector in order to efficiently add them into a sum.
2979
         * i.e. limb_0 =- field_t::accumulate(limb_0_accumulator)
2980
         * This costs us fewer gates than addition operations because we can add 2 values into a sum in a single
2981
         * custom gate.
2982
         **/
2983
2984
0
        std::vector<field_t<Builder>> limb_0_accumulator;
2985
0
        std::vector<field_t<Builder>> limb_2_accumulator;
2986
0
        std::vector<field_t<Builder>> prime_limb_accumulator;
2987
2988
        // Add remaining products into the limb accumulators.
2989
        // We negate the product values because the accumulator values itself will be negated
2990
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
2991
        // that the accumulators originaly tracked the remainder term (which is negated)
2992
2993
0
        for (size_t i = 1; i < num_multiplications; ++i) {
2994
0
            field_t lo_2 = left[i].binary_basis_limbs[0].element * right[i].binary_basis_limbs[0].element;
2995
0
            lo_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[0].element * shift_1, lo_2);
2996
0
            lo_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[1].element * shift_1, lo_2);
2997
0
            field_t hi_2 = left[i].binary_basis_limbs[1].element * right[i].binary_basis_limbs[1].element;
2998
0
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[0].element, hi_2);
2999
0
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[2].element, hi_2);
3000
0
            hi_2 = left[i].binary_basis_limbs[3].element.madd(right[i].binary_basis_limbs[0].element * shift_1, hi_2);
3001
0
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[1].element * shift_1, hi_2);
3002
0
            hi_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[2].element * shift_1, hi_2);
3003
0
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[3].element * shift_1, hi_2);
3004
3005
0
            limb_0_accumulator.emplace_back(-lo_2);
3006
0
            limb_2_accumulator.emplace_back(-hi_2);
3007
0
            prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
3008
0
        }
3009
        // add cached products into the limb accumulators.
3010
        // We negate the cache values because the accumulator values itself will be negated
3011
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
3012
        // that the accumulators originaly tracked the remainder term (which is negated)
3013
3014
        // Update the accumulators with the remainder terms. First check we actually have remainder terms!
3015
        //(not present when we're checking a product is 0 mod p). See `assert_is_in_field`
3016
3017
0
        bool no_remainders = remainders.size() == 0;
3018
0
        if (!no_remainders) {
3019
0
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
3020
0
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
3021
0
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
3022
0
        }
3023
0
        for (size_t i = 1; i < remainders.size(); ++i) {
3024
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
3025
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
3026
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
3027
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
3028
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
3029
0
        }
3030
0
        for (const auto& add : to_add) {
3031
0
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
3032
0
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
3033
0
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
3034
0
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
3035
0
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
3036
0
        }
3037
3038
0
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
3039
0
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
3040
0
        if (accumulated_lo.is_constant()) {
3041
0
            accumulated_lo =
3042
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
3043
0
        }
3044
0
        if (accumulated_hi.is_constant()) {
3045
0
            accumulated_hi =
3046
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
3047
0
        }
3048
0
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3049
0
                                                    : remainders[0].binary_basis_limbs[1].element;
3050
0
        if (remainder1.is_constant()) {
3051
0
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
3052
0
        }
3053
0
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3054
0
                                                    : remainders[0].binary_basis_limbs[3].element;
3055
0
        if (remainder3.is_constant()) {
3056
0
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
3057
0
        }
3058
0
        field_t<Builder> remainder_limbs[4]{
3059
0
            accumulated_lo,
3060
0
            remainder1,
3061
0
            accumulated_hi,
3062
0
            remainder3,
3063
0
        };
3064
0
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
3065
3066
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
3067
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
3068
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
3069
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
3070
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
3071
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
3072
3073
0
        field_t r0 = left[0].binary_basis_limbs[0].element.madd(
3074
0
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3075
0
        field_t r1 = b0.add_two(b1, -remainder_limbs[1]);
3076
0
        const field_t r2 = c0.add_two(c1, c2);
3077
0
        const field_t r3 = d0 + d1.add_two(d2, d3);
3078
3079
0
        field_t carry_lo_0 = r0 * shift_right_2;
3080
0
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3081
0
        field_t carry_lo_2 = -(remainder_limbs[0] * shift_right_2);
3082
0
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3083
3084
0
        field_t t1 = carry_lo.add_two(-remainder_limbs[2], -(remainder_limbs[3] * shift_1));
3085
0
        carry_lo += borrow_lo;
3086
0
        field_t carry_hi_0 = r2 * shift_right_2;
3087
0
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3088
0
        field_t carry_hi_2 = t1 * shift_right_2;
3089
0
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3090
3091
0
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3092
3093
0
        field_t<Builder> linear_terms(ctx, bb::fr(0));
3094
3095
0
        linear_terms += -remainder_prime_limb;
3096
3097
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
3098
0
        field_t<Builder>::evaluate_polynomial_identity(
3099
0
            left[0].prime_basis_limb, right[0].prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3100
3101
0
        const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3102
0
        const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3103
3104
0
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3105
3106
0
        if constexpr (HasPlookup<Builder>) {
3107
0
            carry_lo = carry_lo.normalize();
3108
0
            carry_hi = carry_hi.normalize();
3109
0
            ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(),
3110
0
                                              static_cast<size_t>(carry_lo_msb));
3111
0
            ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(),
3112
0
                                              static_cast<size_t>(carry_hi_msb));
3113
3114
0
        } else {
3115
0
            if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3116
0
                field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3117
0
                carry_combined = carry_combined.normalize();
3118
0
                const auto accumulators = ctx->decompose_into_base4_accumulators(
3119
0
                    carry_combined.get_normalized_witness_index(),
3120
0
                    static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3121
0
                    "bigfield: carry_combined too large in unsafe_evaluate_multiple_multiply_add.");
3122
0
                field_t<Builder> accumulator_midpoint = field_t<Builder>::from_witness_index(
3123
0
                    ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3124
0
                carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3125
0
            } else {
3126
0
                carry_lo = carry_lo.normalize();
3127
0
                carry_hi = carry_hi.normalize();
3128
0
                ctx->decompose_into_base4_accumulators(
3129
0
                    carry_lo.get_normalized_witness_index(),
3130
0
                    static_cast<size_t>(carry_lo_msb),
3131
0
                    "bigfield: carry_lo too large in unsafe_evaluate_multiple_multiply_add.");
3132
0
                ctx->decompose_into_base4_accumulators(
3133
0
                    carry_hi.get_normalized_witness_index(),
3134
0
                    static_cast<size_t>(carry_hi_msb),
3135
0
                    "bigfield: carry_hi too large in unsafe_evaluate_multiple_multiply_add.");
3136
0
            }
3137
0
        }
3138
0
    }
3139
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_
Line
Count
Source
2608
338k
{
2609
338k
    ASSERT(input_left.size() == input_right.size());
2610
338k
    ASSERT(input_left.size() <= MAXIMUM_SUMMAND_COUNT);
2611
338k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2612
338k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2613
2614
338k
    ASSERT(input_left.size() == input_right.size() && input_left.size() < 1024);
2615
    // Sanity checks
2616
743k
    for (auto& el : input_left) {
2617
743k
        el.sanity_check();
2618
743k
    }
2619
743k
    for (auto& el : input_right) {
2620
743k
        el.sanity_check();
2621
743k
    }
2622
615k
    for (auto& el : to_add) {
2623
615k
        el.sanity_check();
2624
615k
    }
2625
338k
    input_quotient.sanity_check();
2626
338k
    for (auto& el : input_remainders) {
2627
338k
        el.sanity_check();
2628
338k
    }
2629
338k
    std::vector<bigfield> remainders(input_remainders);
2630
338k
    std::vector<bigfield> left(input_left);
2631
338k
    std::vector<bigfield> right(input_right);
2632
338k
    bigfield quotient = input_quotient;
2633
338k
    const size_t num_multiplications = input_left.size();
2634
2635
338k
    Builder* ctx = input_left[0].context ? input_left[0].context : input_right[0].context;
2636
2637
338k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
338k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
338k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
338k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
338k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
338k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
338k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
338k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
338k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
338k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
338k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
338k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
338k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
338k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
338k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
338k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
338k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
338k
    };
2656
2657
    /**
2658
     * Step 1: Compute the maximum potential value of our product limbs
2659
     *
2660
     * max_lo = maximum value of limb products that span the range 0 - 2^{3t}
2661
     * max_hi = maximum value of limb products that span the range 2^{2t} - 2^{5t}
2662
     * (t = NUM_LIMB_BITS)
2663
     **/
2664
338k
    uint512_t max_lo = 0;
2665
338k
    uint512_t max_hi = 0;
2666
2667
    // Compute max values of quotient product limb products
2668
338k
    uint512_t max_b0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2669
338k
    uint512_t max_b1 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2670
338k
    uint512_t max_c0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2671
338k
    uint512_t max_c1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2672
338k
    uint512_t max_c2 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2673
338k
    uint512_t max_d0 = (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2674
338k
    uint512_t max_d1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2675
338k
    uint512_t max_d2 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2676
338k
    uint512_t max_d3 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2677
2678
    // max_r0 = terms from 0 - 2^2t
2679
    // max_r1 = terms from 2^t - 2^3t
2680
    // max_r2 = terms from 2^2t - 2^4t
2681
    // max_r3 = terms from 2^3t - 2^5t
2682
338k
    uint512_t max_r0 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2683
338k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2684
338k
    uint512_t max_r1 = max_b0 + max_b1;
2685
2686
338k
    uint256_t borrow_lo_value(0);
2687
338k
    for (const auto& remainder : input_remainders) {
2688
338k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2689
338k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2690
2691
338k
        borrow_lo_value += remainder.binary_basis_limbs[0].maximum_value +
2692
338k
                           (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2693
338k
    }
2694
338k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2695
338k
    field_t<Builder> borrow_lo(ctx, bb::fr(borrow_lo_value));
2696
2697
338k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2698
338k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2699
2700
    // update max_lo, max_hi with quotient limb product terms.
2701
338k
    max_lo += max_r0 + (max_r1 << NUM_LIMB_BITS);
2702
338k
    max_hi += max_r2 + (max_r3 << NUM_LIMB_BITS);
2703
2704
    // Compute maximum value of addition terms in `to_add` and add to max_lo, max_hi
2705
338k
    uint512_t max_a0(0);
2706
338k
    uint512_t max_a1(0);
2707
954k
    for (size_t i = 0; i < to_add.size(); ++i) {
2708
615k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2709
615k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2710
615k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2711
615k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2712
615k
    }
2713
338k
    max_lo += max_a0;
2714
338k
    max_hi += max_a1;
2715
2716
    // Compute the maximum value of our multiplication products and add to max_lo, max_hi
2717
1.08M
    for (size_t i = 0; i < num_multiplications; ++i) {
2718
743k
        const auto [product_lo, product_hi] = get_product_maximum(left[i], right[i]);
2719
743k
        max_lo += product_lo;
2720
743k
        max_hi += product_hi;
2721
743k
    }
2722
2723
338k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2724
338k
    max_hi += max_lo_carry;
2725
    // Compute the maximum number of bits in `max_lo` and `max_hi` - this defines the range constraint values we
2726
    // will need to apply to validate our product
2727
338k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2728
338k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2729
    // Turbo range checks only work for even bit ranges, so make sure these values are even
2730
    // TODO: This neccessary anymore? Turbo range checks now work with odd bit ranges...
2731
338k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2732
62.6k
        ++max_lo_bits;
2733
62.6k
    }
2734
338k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2735
307k
        ++max_hi_bits;
2736
307k
    }
2737
2738
338k
    if constexpr (HasPlookup<Builder>) {
2739
        // The plookup custom bigfield gate requires inputs are witnesses.
2740
        // If we're using constant values, instantiate them as circuit variables
2741
2742
338k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2743
338k
            bigfield output(input);
2744
338k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2745
338k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2746
338k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2747
338k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2748
338k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2749
338k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2750
338k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2751
338k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2752
338k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2753
338k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2754
338k
            output.context = ctx;
2755
338k
            return output;
2756
338k
        };
2757
2758
        // evalaute a nnf mul and add into existing lohi output for our extra product terms
2759
        // we need to add the result of (left_b * right_b) into lo_1_idx and hi_1_idx
2760
        // our custom gate evaluates: ((a * b) + (q * neg_modulus) - r) / 2^{136} = lo + hi * 2^{136}
2761
        // where q is a 'quotient' bigfield and neg_modulus is defined by selector polynomial values
2762
        // The custom gate costs 7 constraints, which is cheaper than computing `a * b` using multiplication +
2763
        // addition gates But....we want to obtain `left_a * right_b + lo_1 + hi_1 * 2^{136} = lo + hi * 2^{136}` If
2764
        // we set `neg_modulus = [2^{136}, 0, 0, 0]` and `q = [lo_1, 0, hi_1, 0]`, then we will add `lo_1` into
2765
        // `lo`, and `lo_1/2^{136} + hi_1` into `hi`. we can then subtract off `lo_1/2^{136}` from `hi`, by setting
2766
        // `r = [0, 0, lo_1, 0]` This saves us 2 addition gates as we don't have to add together the outputs of two
2767
        // calls to `evaluate_non_native_field_multiplication`
2768
338k
        std::vector<field_t<Builder>> limb_0_accumulator;
2769
338k
        std::vector<field_t<Builder>> limb_2_accumulator;
2770
338k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2771
2772
1.08M
        for (size_t i = 0; i < num_multiplications; ++i) {
2773
743k
            if (i == 0 && left[0].is_constant()) {
2774
0
                left[0] = convert_constant_to_fixed_witness(left[0]);
2775
0
            }
2776
743k
            if (i == 0 && right[0].is_constant()) {
2777
1
                right[0] = convert_constant_to_fixed_witness(right[0]);
2778
1
            }
2779
743k
            if (i > 0 && left[i].is_constant()) {
2780
0
                left[i] = convert_constant_to_fixed_witness(left[i]);
2781
0
            }
2782
743k
            if (i > 0 && right[i].is_constant()) {
2783
0
                right[i] = convert_constant_to_fixed_witness(right[i]);
2784
0
            }
2785
2786
743k
            if (i > 0) {
2787
405k
                bb::non_native_field_witnesses<bb::fr> mul_witnesses = {
2788
405k
                    {
2789
405k
                        left[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2790
405k
                        left[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2791
405k
                        left[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2792
405k
                        left[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2793
405k
                    },
2794
405k
                    {
2795
405k
                        right[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2796
405k
                        right[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2797
405k
                        right[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2798
405k
                        right[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2799
405k
                    },
2800
405k
                    {
2801
405k
                        ctx->zero_idx,
2802
405k
                        ctx->zero_idx,
2803
405k
                        ctx->zero_idx,
2804
405k
                        ctx->zero_idx,
2805
405k
                    },
2806
405k
                    {
2807
405k
                        ctx->zero_idx,
2808
405k
                        ctx->zero_idx,
2809
405k
                        ctx->zero_idx,
2810
405k
                        ctx->zero_idx,
2811
405k
                    },
2812
405k
                    { 0, 0, 0, 0 },
2813
405k
                    modulus,
2814
405k
                };
2815
2816
405k
                const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses);
2817
2818
405k
                field_t<Builder> lo_2 = field_t<Builder>::from_witness_index(ctx, lo_2_idx);
2819
405k
                field_t<Builder> hi_2 = field_t<Builder>::from_witness_index(ctx, hi_2_idx);
2820
2821
405k
                limb_0_accumulator.emplace_back(-lo_2);
2822
405k
                limb_2_accumulator.emplace_back(-hi_2);
2823
405k
                prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
2824
405k
            }
2825
743k
        }
2826
338k
        if (quotient.is_constant()) {
2827
0
            quotient = convert_constant_to_fixed_witness(quotient);
2828
0
        }
2829
2830
338k
        bool no_remainders = remainders.size() == 0;
2831
338k
        if (!no_remainders) {
2832
338k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
2833
338k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
2834
338k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
2835
338k
        }
2836
338k
        for (size_t i = 1; i < remainders.size(); ++i) {
2837
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2838
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2839
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2840
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2841
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2842
0
        }
2843
615k
        for (const auto& add : to_add) {
2844
615k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2845
615k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2846
615k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2847
615k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2848
615k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2849
615k
        }
2850
2851
338k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
2852
338k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
2853
338k
        if (accumulated_lo.is_constant()) {
2854
0
            accumulated_lo =
2855
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
2856
0
        }
2857
338k
        if (accumulated_hi.is_constant()) {
2858
0
            accumulated_hi =
2859
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
2860
0
        }
2861
338k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2862
338k
                                                    : remainders[0].binary_basis_limbs[1].element;
2863
338k
        if (remainder1.is_constant()) {
2864
0
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
2865
0
        }
2866
338k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2867
338k
                                                    : remainders[0].binary_basis_limbs[3].element;
2868
338k
        if (remainder3.is_constant()) {
2869
0
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
2870
0
        }
2871
338k
        field_t<Builder> remainder_limbs[4]{
2872
338k
            accumulated_lo,
2873
338k
            remainder1,
2874
338k
            accumulated_hi,
2875
338k
            remainder3,
2876
338k
        };
2877
338k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2878
2879
338k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2880
338k
            {
2881
338k
                left[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2882
338k
                left[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2883
338k
                left[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2884
338k
                left[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2885
338k
            },
2886
338k
            {
2887
338k
                right[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2888
338k
                right[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2889
338k
                right[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2890
338k
                right[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2891
338k
            },
2892
338k
            {
2893
338k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2894
338k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2895
338k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2896
338k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2897
338k
            },
2898
338k
            {
2899
338k
                remainder_limbs[0].get_normalized_witness_index(),
2900
338k
                remainder_limbs[1].get_normalized_witness_index(),
2901
338k
                remainder_limbs[2].get_normalized_witness_index(),
2902
338k
                remainder_limbs[3].get_normalized_witness_index(),
2903
338k
            },
2904
338k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2905
338k
            modulus,
2906
338k
        };
2907
2908
338k
        const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2909
2910
338k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2911
2912
338k
        field_t<Builder>::evaluate_polynomial_identity(left[0].prime_basis_limb,
2913
338k
                                                       right[0].prime_basis_limb,
2914
338k
                                                       quotient.prime_basis_limb * neg_prime,
2915
338k
                                                       -remainder_prime_limb);
2916
2917
338k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_1_idx) + borrow_lo;
2918
338k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_1_idx);
2919
2920
338k
        uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2921
338k
        uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2922
2923
338k
        if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2924
0
            carry_lo_msb = 0;
2925
0
        }
2926
338k
        if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2927
0
            carry_hi_msb = 0;
2928
0
        }
2929
2930
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2931
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2932
338k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2933
0
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2934
0
                                           lo.get_normalized_witness_index(),
2935
0
                                           (size_t)carry_hi_msb,
2936
0
                                           (size_t)carry_lo_msb);
2937
338k
        } else {
2938
338k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2939
338k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2940
338k
        }
2941
        /*  NOTE TO AUDITOR: An extraneous block
2942
               if constexpr (HasPlookup<Builder>) {
2943
                   carry_lo = carry_lo.normalize();
2944
                   carry_hi = carry_hi.normalize();
2945
                   ctx->decompose_into_default_range(carry_lo.witness_index, static_cast<size_t>(carry_lo_msb));
2946
                   ctx->decompose_into_default_range(carry_hi.witness_index, static_cast<size_t>(carry_hi_msb));
2947
               }
2948
            was removed from the `else` block below. See  the conversation at
2949
               https://github.com/AztecProtocol/aztec2-internal/pull/1023
2950
            We should make sure that no constraint like this is needed but missing (e.g., an equivalent constraint
2951
            was just imposed?). */
2952
338k
    } else {
2953
338k
        field_t b0 = left[0].binary_basis_limbs[1].element.madd(
2954
338k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2955
338k
        field_t b1 = left[0].binary_basis_limbs[0].element.madd(
2956
338k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2957
338k
        field_t c0 = left[0].binary_basis_limbs[1].element.madd(
2958
338k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2959
338k
        field_t c1 = left[0].binary_basis_limbs[2].element.madd(
2960
338k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2961
338k
        field_t c2 = left[0].binary_basis_limbs[0].element.madd(
2962
338k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2963
338k
        field_t d0 = left[0].binary_basis_limbs[3].element.madd(
2964
338k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2965
338k
        field_t d1 = left[0].binary_basis_limbs[2].element.madd(
2966
338k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2967
338k
        field_t d2 = left[0].binary_basis_limbs[1].element.madd(
2968
338k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2969
338k
        field_t d3 = left[0].binary_basis_limbs[0].element.madd(
2970
338k
            right[0].binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2971
2972
        /**
2973
         * Compute "limb accumulators"
2974
         * `limb_0_accumulator` contains contributions in the range 0 - 2^{3t}
2975
         * `limb_2_accumulator` contains contributiosn in the range 2^{2t} - 2^{5t} (t = MAX_NUM_LIMB_BITS)
2976
         * Actual range will vary a few bits because of lazy reduction techniques
2977
         *
2978
         * We store these values in an "accumulator" vector in order to efficiently add them into a sum.
2979
         * i.e. limb_0 =- field_t::accumulate(limb_0_accumulator)
2980
         * This costs us fewer gates than addition operations because we can add 2 values into a sum in a single
2981
         * custom gate.
2982
         **/
2983
2984
338k
        std::vector<field_t<Builder>> limb_0_accumulator;
2985
338k
        std::vector<field_t<Builder>> limb_2_accumulator;
2986
338k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2987
2988
        // Add remaining products into the limb accumulators.
2989
        // We negate the product values because the accumulator values itself will be negated
2990
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
2991
        // that the accumulators originaly tracked the remainder term (which is negated)
2992
2993
338k
        for (size_t i = 1; i < num_multiplications; ++i) {
2994
338k
            field_t lo_2 = left[i].binary_basis_limbs[0].element * right[i].binary_basis_limbs[0].element;
2995
338k
            lo_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[0].element * shift_1, lo_2);
2996
338k
            lo_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[1].element * shift_1, lo_2);
2997
338k
            field_t hi_2 = left[i].binary_basis_limbs[1].element * right[i].binary_basis_limbs[1].element;
2998
338k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[0].element, hi_2);
2999
338k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[2].element, hi_2);
3000
338k
            hi_2 = left[i].binary_basis_limbs[3].element.madd(right[i].binary_basis_limbs[0].element * shift_1, hi_2);
3001
338k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[1].element * shift_1, hi_2);
3002
338k
            hi_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[2].element * shift_1, hi_2);
3003
338k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[3].element * shift_1, hi_2);
3004
3005
338k
            limb_0_accumulator.emplace_back(-lo_2);
3006
338k
            limb_2_accumulator.emplace_back(-hi_2);
3007
338k
            prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
3008
338k
        }
3009
        // add cached products into the limb accumulators.
3010
        // We negate the cache values because the accumulator values itself will be negated
3011
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
3012
        // that the accumulators originaly tracked the remainder term (which is negated)
3013
3014
        // Update the accumulators with the remainder terms. First check we actually have remainder terms!
3015
        //(not present when we're checking a product is 0 mod p). See `assert_is_in_field`
3016
3017
338k
        bool no_remainders = remainders.size() == 0;
3018
338k
        if (!no_remainders) {
3019
338k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
3020
338k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
3021
338k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
3022
338k
        }
3023
338k
        for (size_t i = 1; i < remainders.size(); ++i) {
3024
338k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
3025
338k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
3026
338k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
3027
338k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
3028
338k
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
3029
338k
        }
3030
338k
        for (const auto& add : to_add) {
3031
338k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
3032
338k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
3033
338k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
3034
338k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
3035
338k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
3036
338k
        }
3037
3038
338k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
3039
338k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
3040
338k
        if (accumulated_lo.is_constant()) {
3041
338k
            accumulated_lo =
3042
338k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
3043
338k
        }
3044
338k
        if (accumulated_hi.is_constant()) {
3045
338k
            accumulated_hi =
3046
338k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
3047
338k
        }
3048
338k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3049
338k
                                                    : remainders[0].binary_basis_limbs[1].element;
3050
338k
        if (remainder1.is_constant()) {
3051
338k
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
3052
338k
        }
3053
338k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3054
338k
                                                    : remainders[0].binary_basis_limbs[3].element;
3055
338k
        if (remainder3.is_constant()) {
3056
338k
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
3057
338k
        }
3058
338k
        field_t<Builder> remainder_limbs[4]{
3059
338k
            accumulated_lo,
3060
338k
            remainder1,
3061
338k
            accumulated_hi,
3062
338k
            remainder3,
3063
338k
        };
3064
338k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
3065
3066
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
3067
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
3068
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
3069
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
3070
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
3071
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
3072
3073
338k
        field_t r0 = left[0].binary_basis_limbs[0].element.madd(
3074
338k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3075
338k
        field_t r1 = b0.add_two(b1, -remainder_limbs[1]);
3076
338k
        const field_t r2 = c0.add_two(c1, c2);
3077
338k
        const field_t r3 = d0 + d1.add_two(d2, d3);
3078
3079
338k
        field_t carry_lo_0 = r0 * shift_right_2;
3080
338k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3081
338k
        field_t carry_lo_2 = -(remainder_limbs[0] * shift_right_2);
3082
338k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3083
3084
338k
        field_t t1 = carry_lo.add_two(-remainder_limbs[2], -(remainder_limbs[3] * shift_1));
3085
338k
        carry_lo += borrow_lo;
3086
338k
        field_t carry_hi_0 = r2 * shift_right_2;
3087
338k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3088
338k
        field_t carry_hi_2 = t1 * shift_right_2;
3089
338k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3090
3091
338k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3092
3093
338k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
3094
3095
338k
        linear_terms += -remainder_prime_limb;
3096
3097
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
3098
338k
        field_t<Builder>::evaluate_polynomial_identity(
3099
338k
            left[0].prime_basis_limb, right[0].prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3100
3101
338k
        const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3102
338k
        const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3103
3104
338k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3105
3106
338k
        if constexpr (HasPlookup<Builder>) {
3107
338k
            carry_lo = carry_lo.normalize();
3108
338k
            carry_hi = carry_hi.normalize();
3109
338k
            ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(),
3110
338k
                                              static_cast<size_t>(carry_lo_msb));
3111
338k
            ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(),
3112
338k
                                              static_cast<size_t>(carry_hi_msb));
3113
3114
338k
        } else {
3115
338k
            if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3116
338k
                field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3117
338k
                carry_combined = carry_combined.normalize();
3118
338k
                const auto accumulators = ctx->decompose_into_base4_accumulators(
3119
338k
                    carry_combined.get_normalized_witness_index(),
3120
338k
                    static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3121
338k
                    "bigfield: carry_combined too large in unsafe_evaluate_multiple_multiply_add.");
3122
338k
                field_t<Builder> accumulator_midpoint = field_t<Builder>::from_witness_index(
3123
338k
                    ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3124
338k
                carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3125
338k
            } else {
3126
338k
                carry_lo = carry_lo.normalize();
3127
338k
                carry_hi = carry_hi.normalize();
3128
338k
                ctx->decompose_into_base4_accumulators(
3129
338k
                    carry_lo.get_normalized_witness_index(),
3130
338k
                    static_cast<size_t>(carry_lo_msb),
3131
338k
                    "bigfield: carry_lo too large in unsafe_evaluate_multiple_multiply_add.");
3132
338k
                ctx->decompose_into_base4_accumulators(
3133
338k
                    carry_hi.get_normalized_witness_index(),
3134
338k
                    static_cast<size_t>(carry_hi_msb),
3135
338k
                    "bigfield: carry_hi too large in unsafe_evaluate_multiple_multiply_add.");
3136
338k
            }
3137
338k
        }
3138
338k
    }
3139
338k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS8_SaIS8_EESD_SD_RKS8_SD_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_
Line
Count
Source
2608
1.29k
{
2609
1.29k
    ASSERT(input_left.size() == input_right.size());
2610
1.29k
    ASSERT(input_left.size() <= MAXIMUM_SUMMAND_COUNT);
2611
1.29k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2612
1.29k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2613
2614
1.29k
    ASSERT(input_left.size() == input_right.size() && input_left.size() < 1024);
2615
    // Sanity checks
2616
3.15k
    for (auto& el : input_left) {
2617
3.15k
        el.sanity_check();
2618
3.15k
    }
2619
3.15k
    for (auto& el : input_right) {
2620
3.15k
        el.sanity_check();
2621
3.15k
    }
2622
1.37k
    for (auto& el : to_add) {
2623
1.37k
        el.sanity_check();
2624
1.37k
    }
2625
1.29k
    input_quotient.sanity_check();
2626
1.29k
    for (auto& el : input_remainders) {
2627
1.29k
        el.sanity_check();
2628
1.29k
    }
2629
1.29k
    std::vector<bigfield> remainders(input_remainders);
2630
1.29k
    std::vector<bigfield> left(input_left);
2631
1.29k
    std::vector<bigfield> right(input_right);
2632
1.29k
    bigfield quotient = input_quotient;
2633
1.29k
    const size_t num_multiplications = input_left.size();
2634
2635
1.29k
    Builder* ctx = input_left[0].context ? input_left[0].context : input_right[0].context;
2636
2637
1.29k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
1.29k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
1.29k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
1.29k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
1.29k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
1.29k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
1.29k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
1.29k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
1.29k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
1.29k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
1.29k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
1.29k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
1.29k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
1.29k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
1.29k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
1.29k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
1.29k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
1.29k
    };
2656
2657
    /**
2658
     * Step 1: Compute the maximum potential value of our product limbs
2659
     *
2660
     * max_lo = maximum value of limb products that span the range 0 - 2^{3t}
2661
     * max_hi = maximum value of limb products that span the range 2^{2t} - 2^{5t}
2662
     * (t = NUM_LIMB_BITS)
2663
     **/
2664
1.29k
    uint512_t max_lo = 0;
2665
1.29k
    uint512_t max_hi = 0;
2666
2667
    // Compute max values of quotient product limb products
2668
1.29k
    uint512_t max_b0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2669
1.29k
    uint512_t max_b1 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2670
1.29k
    uint512_t max_c0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2671
1.29k
    uint512_t max_c1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2672
1.29k
    uint512_t max_c2 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2673
1.29k
    uint512_t max_d0 = (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2674
1.29k
    uint512_t max_d1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2675
1.29k
    uint512_t max_d2 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2676
1.29k
    uint512_t max_d3 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2677
2678
    // max_r0 = terms from 0 - 2^2t
2679
    // max_r1 = terms from 2^t - 2^3t
2680
    // max_r2 = terms from 2^2t - 2^4t
2681
    // max_r3 = terms from 2^3t - 2^5t
2682
1.29k
    uint512_t max_r0 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2683
1.29k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2684
1.29k
    uint512_t max_r1 = max_b0 + max_b1;
2685
2686
1.29k
    uint256_t borrow_lo_value(0);
2687
1.29k
    for (const auto& remainder : input_remainders) {
2688
1.29k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2689
1.29k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2690
2691
1.29k
        borrow_lo_value += remainder.binary_basis_limbs[0].maximum_value +
2692
1.29k
                           (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2693
1.29k
    }
2694
1.29k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2695
1.29k
    field_t<Builder> borrow_lo(ctx, bb::fr(borrow_lo_value));
2696
2697
1.29k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2698
1.29k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2699
2700
    // update max_lo, max_hi with quotient limb product terms.
2701
1.29k
    max_lo += max_r0 + (max_r1 << NUM_LIMB_BITS);
2702
1.29k
    max_hi += max_r2 + (max_r3 << NUM_LIMB_BITS);
2703
2704
    // Compute maximum value of addition terms in `to_add` and add to max_lo, max_hi
2705
1.29k
    uint512_t max_a0(0);
2706
1.29k
    uint512_t max_a1(0);
2707
2.66k
    for (size_t i = 0; i < to_add.size(); ++i) {
2708
1.37k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2709
1.37k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2710
1.37k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2711
1.37k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2712
1.37k
    }
2713
1.29k
    max_lo += max_a0;
2714
1.29k
    max_hi += max_a1;
2715
2716
    // Compute the maximum value of our multiplication products and add to max_lo, max_hi
2717
4.44k
    for (size_t i = 0; i < num_multiplications; ++i) {
2718
3.15k
        const auto [product_lo, product_hi] = get_product_maximum(left[i], right[i]);
2719
3.15k
        max_lo += product_lo;
2720
3.15k
        max_hi += product_hi;
2721
3.15k
    }
2722
2723
1.29k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2724
1.29k
    max_hi += max_lo_carry;
2725
    // Compute the maximum number of bits in `max_lo` and `max_hi` - this defines the range constraint values we
2726
    // will need to apply to validate our product
2727
1.29k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2728
1.29k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2729
    // Turbo range checks only work for even bit ranges, so make sure these values are even
2730
    // TODO: This neccessary anymore? Turbo range checks now work with odd bit ranges...
2731
1.29k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2732
585
        ++max_lo_bits;
2733
585
    }
2734
1.29k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2735
594
        ++max_hi_bits;
2736
594
    }
2737
2738
1.29k
    if constexpr (HasPlookup<Builder>) {
2739
        // The plookup custom bigfield gate requires inputs are witnesses.
2740
        // If we're using constant values, instantiate them as circuit variables
2741
2742
1.29k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2743
1.29k
            bigfield output(input);
2744
1.29k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2745
1.29k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2746
1.29k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2747
1.29k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2748
1.29k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2749
1.29k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2750
1.29k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2751
1.29k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2752
1.29k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2753
1.29k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2754
1.29k
            output.context = ctx;
2755
1.29k
            return output;
2756
1.29k
        };
2757
2758
        // evalaute a nnf mul and add into existing lohi output for our extra product terms
2759
        // we need to add the result of (left_b * right_b) into lo_1_idx and hi_1_idx
2760
        // our custom gate evaluates: ((a * b) + (q * neg_modulus) - r) / 2^{136} = lo + hi * 2^{136}
2761
        // where q is a 'quotient' bigfield and neg_modulus is defined by selector polynomial values
2762
        // The custom gate costs 7 constraints, which is cheaper than computing `a * b` using multiplication +
2763
        // addition gates But....we want to obtain `left_a * right_b + lo_1 + hi_1 * 2^{136} = lo + hi * 2^{136}` If
2764
        // we set `neg_modulus = [2^{136}, 0, 0, 0]` and `q = [lo_1, 0, hi_1, 0]`, then we will add `lo_1` into
2765
        // `lo`, and `lo_1/2^{136} + hi_1` into `hi`. we can then subtract off `lo_1/2^{136}` from `hi`, by setting
2766
        // `r = [0, 0, lo_1, 0]` This saves us 2 addition gates as we don't have to add together the outputs of two
2767
        // calls to `evaluate_non_native_field_multiplication`
2768
1.29k
        std::vector<field_t<Builder>> limb_0_accumulator;
2769
1.29k
        std::vector<field_t<Builder>> limb_2_accumulator;
2770
1.29k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2771
2772
4.44k
        for (size_t i = 0; i < num_multiplications; ++i) {
2773
3.15k
            if (i == 0 && left[0].is_constant()) {
2774
0
                left[0] = convert_constant_to_fixed_witness(left[0]);
2775
0
            }
2776
3.15k
            if (i == 0 && right[0].is_constant()) {
2777
0
                right[0] = convert_constant_to_fixed_witness(right[0]);
2778
0
            }
2779
3.15k
            if (i > 0 && left[i].is_constant()) {
2780
0
                left[i] = convert_constant_to_fixed_witness(left[i]);
2781
0
            }
2782
3.15k
            if (i > 0 && right[i].is_constant()) {
2783
0
                right[i] = convert_constant_to_fixed_witness(right[i]);
2784
0
            }
2785
2786
3.15k
            if (i > 0) {
2787
1.86k
                bb::non_native_field_witnesses<bb::fr> mul_witnesses = {
2788
1.86k
                    {
2789
1.86k
                        left[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2790
1.86k
                        left[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2791
1.86k
                        left[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2792
1.86k
                        left[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2793
1.86k
                    },
2794
1.86k
                    {
2795
1.86k
                        right[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2796
1.86k
                        right[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2797
1.86k
                        right[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2798
1.86k
                        right[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2799
1.86k
                    },
2800
1.86k
                    {
2801
1.86k
                        ctx->zero_idx,
2802
1.86k
                        ctx->zero_idx,
2803
1.86k
                        ctx->zero_idx,
2804
1.86k
                        ctx->zero_idx,
2805
1.86k
                    },
2806
1.86k
                    {
2807
1.86k
                        ctx->zero_idx,
2808
1.86k
                        ctx->zero_idx,
2809
1.86k
                        ctx->zero_idx,
2810
1.86k
                        ctx->zero_idx,
2811
1.86k
                    },
2812
1.86k
                    { 0, 0, 0, 0 },
2813
1.86k
                    modulus,
2814
1.86k
                };
2815
2816
1.86k
                const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses);
2817
2818
1.86k
                field_t<Builder> lo_2 = field_t<Builder>::from_witness_index(ctx, lo_2_idx);
2819
1.86k
                field_t<Builder> hi_2 = field_t<Builder>::from_witness_index(ctx, hi_2_idx);
2820
2821
1.86k
                limb_0_accumulator.emplace_back(-lo_2);
2822
1.86k
                limb_2_accumulator.emplace_back(-hi_2);
2823
1.86k
                prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
2824
1.86k
            }
2825
3.15k
        }
2826
1.29k
        if (quotient.is_constant()) {
2827
0
            quotient = convert_constant_to_fixed_witness(quotient);
2828
0
        }
2829
2830
1.29k
        bool no_remainders = remainders.size() == 0;
2831
1.29k
        if (!no_remainders) {
2832
1.29k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
2833
1.29k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
2834
1.29k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
2835
1.29k
        }
2836
1.29k
        for (size_t i = 1; i < remainders.size(); ++i) {
2837
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2838
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2839
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2840
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2841
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2842
0
        }
2843
1.37k
        for (const auto& add : to_add) {
2844
1.37k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2845
1.37k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2846
1.37k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2847
1.37k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2848
1.37k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2849
1.37k
        }
2850
2851
1.29k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
2852
1.29k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
2853
1.29k
        if (accumulated_lo.is_constant()) {
2854
0
            accumulated_lo =
2855
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
2856
0
        }
2857
1.29k
        if (accumulated_hi.is_constant()) {
2858
0
            accumulated_hi =
2859
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
2860
0
        }
2861
1.29k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2862
1.29k
                                                    : remainders[0].binary_basis_limbs[1].element;
2863
1.29k
        if (remainder1.is_constant()) {
2864
0
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
2865
0
        }
2866
1.29k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2867
1.29k
                                                    : remainders[0].binary_basis_limbs[3].element;
2868
1.29k
        if (remainder3.is_constant()) {
2869
0
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
2870
0
        }
2871
1.29k
        field_t<Builder> remainder_limbs[4]{
2872
1.29k
            accumulated_lo,
2873
1.29k
            remainder1,
2874
1.29k
            accumulated_hi,
2875
1.29k
            remainder3,
2876
1.29k
        };
2877
1.29k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2878
2879
1.29k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2880
1.29k
            {
2881
1.29k
                left[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2882
1.29k
                left[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2883
1.29k
                left[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2884
1.29k
                left[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2885
1.29k
            },
2886
1.29k
            {
2887
1.29k
                right[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2888
1.29k
                right[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2889
1.29k
                right[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2890
1.29k
                right[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2891
1.29k
            },
2892
1.29k
            {
2893
1.29k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2894
1.29k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2895
1.29k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2896
1.29k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2897
1.29k
            },
2898
1.29k
            {
2899
1.29k
                remainder_limbs[0].get_normalized_witness_index(),
2900
1.29k
                remainder_limbs[1].get_normalized_witness_index(),
2901
1.29k
                remainder_limbs[2].get_normalized_witness_index(),
2902
1.29k
                remainder_limbs[3].get_normalized_witness_index(),
2903
1.29k
            },
2904
1.29k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2905
1.29k
            modulus,
2906
1.29k
        };
2907
2908
1.29k
        const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2909
2910
1.29k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2911
2912
1.29k
        field_t<Builder>::evaluate_polynomial_identity(left[0].prime_basis_limb,
2913
1.29k
                                                       right[0].prime_basis_limb,
2914
1.29k
                                                       quotient.prime_basis_limb * neg_prime,
2915
1.29k
                                                       -remainder_prime_limb);
2916
2917
1.29k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_1_idx) + borrow_lo;
2918
1.29k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_1_idx);
2919
2920
1.29k
        uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2921
1.29k
        uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2922
2923
1.29k
        if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2924
0
            carry_lo_msb = 0;
2925
0
        }
2926
1.29k
        if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2927
0
            carry_hi_msb = 0;
2928
0
        }
2929
2930
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2931
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2932
1.29k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2933
0
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2934
0
                                           lo.get_normalized_witness_index(),
2935
0
                                           (size_t)carry_hi_msb,
2936
0
                                           (size_t)carry_lo_msb);
2937
1.29k
        } else {
2938
1.29k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2939
1.29k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2940
1.29k
        }
2941
        /*  NOTE TO AUDITOR: An extraneous block
2942
               if constexpr (HasPlookup<Builder>) {
2943
                   carry_lo = carry_lo.normalize();
2944
                   carry_hi = carry_hi.normalize();
2945
                   ctx->decompose_into_default_range(carry_lo.witness_index, static_cast<size_t>(carry_lo_msb));
2946
                   ctx->decompose_into_default_range(carry_hi.witness_index, static_cast<size_t>(carry_hi_msb));
2947
               }
2948
            was removed from the `else` block below. See  the conversation at
2949
               https://github.com/AztecProtocol/aztec2-internal/pull/1023
2950
            We should make sure that no constraint like this is needed but missing (e.g., an equivalent constraint
2951
            was just imposed?). */
2952
1.29k
    } else {
2953
1.29k
        field_t b0 = left[0].binary_basis_limbs[1].element.madd(
2954
1.29k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2955
1.29k
        field_t b1 = left[0].binary_basis_limbs[0].element.madd(
2956
1.29k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2957
1.29k
        field_t c0 = left[0].binary_basis_limbs[1].element.madd(
2958
1.29k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2959
1.29k
        field_t c1 = left[0].binary_basis_limbs[2].element.madd(
2960
1.29k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2961
1.29k
        field_t c2 = left[0].binary_basis_limbs[0].element.madd(
2962
1.29k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2963
1.29k
        field_t d0 = left[0].binary_basis_limbs[3].element.madd(
2964
1.29k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2965
1.29k
        field_t d1 = left[0].binary_basis_limbs[2].element.madd(
2966
1.29k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2967
1.29k
        field_t d2 = left[0].binary_basis_limbs[1].element.madd(
2968
1.29k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2969
1.29k
        field_t d3 = left[0].binary_basis_limbs[0].element.madd(
2970
1.29k
            right[0].binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2971
2972
        /**
2973
         * Compute "limb accumulators"
2974
         * `limb_0_accumulator` contains contributions in the range 0 - 2^{3t}
2975
         * `limb_2_accumulator` contains contributiosn in the range 2^{2t} - 2^{5t} (t = MAX_NUM_LIMB_BITS)
2976
         * Actual range will vary a few bits because of lazy reduction techniques
2977
         *
2978
         * We store these values in an "accumulator" vector in order to efficiently add them into a sum.
2979
         * i.e. limb_0 =- field_t::accumulate(limb_0_accumulator)
2980
         * This costs us fewer gates than addition operations because we can add 2 values into a sum in a single
2981
         * custom gate.
2982
         **/
2983
2984
1.29k
        std::vector<field_t<Builder>> limb_0_accumulator;
2985
1.29k
        std::vector<field_t<Builder>> limb_2_accumulator;
2986
1.29k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2987
2988
        // Add remaining products into the limb accumulators.
2989
        // We negate the product values because the accumulator values itself will be negated
2990
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
2991
        // that the accumulators originaly tracked the remainder term (which is negated)
2992
2993
1.29k
        for (size_t i = 1; i < num_multiplications; ++i) {
2994
1.29k
            field_t lo_2 = left[i].binary_basis_limbs[0].element * right[i].binary_basis_limbs[0].element;
2995
1.29k
            lo_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[0].element * shift_1, lo_2);
2996
1.29k
            lo_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[1].element * shift_1, lo_2);
2997
1.29k
            field_t hi_2 = left[i].binary_basis_limbs[1].element * right[i].binary_basis_limbs[1].element;
2998
1.29k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[0].element, hi_2);
2999
1.29k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[2].element, hi_2);
3000
1.29k
            hi_2 = left[i].binary_basis_limbs[3].element.madd(right[i].binary_basis_limbs[0].element * shift_1, hi_2);
3001
1.29k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[1].element * shift_1, hi_2);
3002
1.29k
            hi_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[2].element * shift_1, hi_2);
3003
1.29k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[3].element * shift_1, hi_2);
3004
3005
1.29k
            limb_0_accumulator.emplace_back(-lo_2);
3006
1.29k
            limb_2_accumulator.emplace_back(-hi_2);
3007
1.29k
            prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
3008
1.29k
        }
3009
        // add cached products into the limb accumulators.
3010
        // We negate the cache values because the accumulator values itself will be negated
3011
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
3012
        // that the accumulators originaly tracked the remainder term (which is negated)
3013
3014
        // Update the accumulators with the remainder terms. First check we actually have remainder terms!
3015
        //(not present when we're checking a product is 0 mod p). See `assert_is_in_field`
3016
3017
1.29k
        bool no_remainders = remainders.size() == 0;
3018
1.29k
        if (!no_remainders) {
3019
1.29k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
3020
1.29k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
3021
1.29k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
3022
1.29k
        }
3023
1.29k
        for (size_t i = 1; i < remainders.size(); ++i) {
3024
1.29k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
3025
1.29k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
3026
1.29k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
3027
1.29k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
3028
1.29k
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
3029
1.29k
        }
3030
1.29k
        for (const auto& add : to_add) {
3031
1.29k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
3032
1.29k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
3033
1.29k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
3034
1.29k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
3035
1.29k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
3036
1.29k
        }
3037
3038
1.29k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
3039
1.29k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
3040
1.29k
        if (accumulated_lo.is_constant()) {
3041
1.29k
            accumulated_lo =
3042
1.29k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
3043
1.29k
        }
3044
1.29k
        if (accumulated_hi.is_constant()) {
3045
1.29k
            accumulated_hi =
3046
1.29k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
3047
1.29k
        }
3048
1.29k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3049
1.29k
                                                    : remainders[0].binary_basis_limbs[1].element;
3050
1.29k
        if (remainder1.is_constant()) {
3051
1.29k
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
3052
1.29k
        }
3053
1.29k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3054
1.29k
                                                    : remainders[0].binary_basis_limbs[3].element;
3055
1.29k
        if (remainder3.is_constant()) {
3056
1.29k
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
3057
1.29k
        }
3058
1.29k
        field_t<Builder> remainder_limbs[4]{
3059
1.29k
            accumulated_lo,
3060
1.29k
            remainder1,
3061
1.29k
            accumulated_hi,
3062
1.29k
            remainder3,
3063
1.29k
        };
3064
1.29k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
3065
3066
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
3067
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
3068
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
3069
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
3070
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
3071
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
3072
3073
1.29k
        field_t r0 = left[0].binary_basis_limbs[0].element.madd(
3074
1.29k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3075
1.29k
        field_t r1 = b0.add_two(b1, -remainder_limbs[1]);
3076
1.29k
        const field_t r2 = c0.add_two(c1, c2);
3077
1.29k
        const field_t r3 = d0 + d1.add_two(d2, d3);
3078
3079
1.29k
        field_t carry_lo_0 = r0 * shift_right_2;
3080
1.29k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3081
1.29k
        field_t carry_lo_2 = -(remainder_limbs[0] * shift_right_2);
3082
1.29k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3083
3084
1.29k
        field_t t1 = carry_lo.add_two(-remainder_limbs[2], -(remainder_limbs[3] * shift_1));
3085
1.29k
        carry_lo += borrow_lo;
3086
1.29k
        field_t carry_hi_0 = r2 * shift_right_2;
3087
1.29k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3088
1.29k
        field_t carry_hi_2 = t1 * shift_right_2;
3089
1.29k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3090
3091
1.29k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3092
3093
1.29k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
3094
3095
1.29k
        linear_terms += -remainder_prime_limb;
3096
3097
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
3098
1.29k
        field_t<Builder>::evaluate_polynomial_identity(
3099
1.29k
            left[0].prime_basis_limb, right[0].prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3100
3101
1.29k
        const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3102
1.29k
        const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3103
3104
1.29k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3105
3106
1.29k
        if constexpr (HasPlookup<Builder>) {
3107
1.29k
            carry_lo = carry_lo.normalize();
3108
1.29k
            carry_hi = carry_hi.normalize();
3109
1.29k
            ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(),
3110
1.29k
                                              static_cast<size_t>(carry_lo_msb));
3111
1.29k
            ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(),
3112
1.29k
                                              static_cast<size_t>(carry_hi_msb));
3113
3114
1.29k
        } else {
3115
1.29k
            if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3116
1.29k
                field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3117
1.29k
                carry_combined = carry_combined.normalize();
3118
1.29k
                const auto accumulators = ctx->decompose_into_base4_accumulators(
3119
1.29k
                    carry_combined.get_normalized_witness_index(),
3120
1.29k
                    static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3121
1.29k
                    "bigfield: carry_combined too large in unsafe_evaluate_multiple_multiply_add.");
3122
1.29k
                field_t<Builder> accumulator_midpoint = field_t<Builder>::from_witness_index(
3123
1.29k
                    ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3124
1.29k
                carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3125
1.29k
            } else {
3126
1.29k
                carry_lo = carry_lo.normalize();
3127
1.29k
                carry_hi = carry_hi.normalize();
3128
1.29k
                ctx->decompose_into_base4_accumulators(
3129
1.29k
                    carry_lo.get_normalized_witness_index(),
3130
1.29k
                    static_cast<size_t>(carry_lo_msb),
3131
1.29k
                    "bigfield: carry_lo too large in unsafe_evaluate_multiple_multiply_add.");
3132
1.29k
                ctx->decompose_into_base4_accumulators(
3133
1.29k
                    carry_hi.get_normalized_witness_index(),
3134
1.29k
                    static_cast<size_t>(carry_hi_msb),
3135
1.29k
                    "bigfield: carry_hi too large in unsafe_evaluate_multiple_multiply_add.");
3136
1.29k
            }
3137
1.29k
        }
3138
1.29k
    }
3139
1.29k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_
Line
Count
Source
2608
28.3k
{
2609
28.3k
    ASSERT(input_left.size() == input_right.size());
2610
28.3k
    ASSERT(input_left.size() <= MAXIMUM_SUMMAND_COUNT);
2611
28.3k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2612
28.3k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2613
2614
28.3k
    ASSERT(input_left.size() == input_right.size() && input_left.size() < 1024);
2615
    // Sanity checks
2616
70.5k
    for (auto& el : input_left) {
2617
70.5k
        el.sanity_check();
2618
70.5k
    }
2619
70.5k
    for (auto& el : input_right) {
2620
70.5k
        el.sanity_check();
2621
70.5k
    }
2622
33.1k
    for (auto& el : to_add) {
2623
33.1k
        el.sanity_check();
2624
33.1k
    }
2625
28.3k
    input_quotient.sanity_check();
2626
28.3k
    for (auto& el : input_remainders) {
2627
28.3k
        el.sanity_check();
2628
28.3k
    }
2629
28.3k
    std::vector<bigfield> remainders(input_remainders);
2630
28.3k
    std::vector<bigfield> left(input_left);
2631
28.3k
    std::vector<bigfield> right(input_right);
2632
28.3k
    bigfield quotient = input_quotient;
2633
28.3k
    const size_t num_multiplications = input_left.size();
2634
2635
28.3k
    Builder* ctx = input_left[0].context ? input_left[0].context : input_right[0].context;
2636
2637
28.3k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
28.3k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
28.3k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
28.3k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
28.3k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
28.3k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
28.3k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
28.3k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
28.3k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
28.3k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
28.3k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
28.3k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
28.3k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
28.3k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
28.3k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
28.3k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
28.3k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
28.3k
    };
2656
2657
    /**
2658
     * Step 1: Compute the maximum potential value of our product limbs
2659
     *
2660
     * max_lo = maximum value of limb products that span the range 0 - 2^{3t}
2661
     * max_hi = maximum value of limb products that span the range 2^{2t} - 2^{5t}
2662
     * (t = NUM_LIMB_BITS)
2663
     **/
2664
28.3k
    uint512_t max_lo = 0;
2665
28.3k
    uint512_t max_hi = 0;
2666
2667
    // Compute max values of quotient product limb products
2668
28.3k
    uint512_t max_b0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2669
28.3k
    uint512_t max_b1 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2670
28.3k
    uint512_t max_c0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2671
28.3k
    uint512_t max_c1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2672
28.3k
    uint512_t max_c2 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2673
28.3k
    uint512_t max_d0 = (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2674
28.3k
    uint512_t max_d1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2675
28.3k
    uint512_t max_d2 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2676
28.3k
    uint512_t max_d3 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2677
2678
    // max_r0 = terms from 0 - 2^2t
2679
    // max_r1 = terms from 2^t - 2^3t
2680
    // max_r2 = terms from 2^2t - 2^4t
2681
    // max_r3 = terms from 2^3t - 2^5t
2682
28.3k
    uint512_t max_r0 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2683
28.3k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2684
28.3k
    uint512_t max_r1 = max_b0 + max_b1;
2685
2686
28.3k
    uint256_t borrow_lo_value(0);
2687
28.3k
    for (const auto& remainder : input_remainders) {
2688
28.3k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2689
28.3k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2690
2691
28.3k
        borrow_lo_value += remainder.binary_basis_limbs[0].maximum_value +
2692
28.3k
                           (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2693
28.3k
    }
2694
28.3k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2695
28.3k
    field_t<Builder> borrow_lo(ctx, bb::fr(borrow_lo_value));
2696
2697
28.3k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2698
28.3k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2699
2700
    // update max_lo, max_hi with quotient limb product terms.
2701
28.3k
    max_lo += max_r0 + (max_r1 << NUM_LIMB_BITS);
2702
28.3k
    max_hi += max_r2 + (max_r3 << NUM_LIMB_BITS);
2703
2704
    // Compute maximum value of addition terms in `to_add` and add to max_lo, max_hi
2705
28.3k
    uint512_t max_a0(0);
2706
28.3k
    uint512_t max_a1(0);
2707
61.4k
    for (size_t i = 0; i < to_add.size(); ++i) {
2708
33.1k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2709
33.1k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2710
33.1k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2711
33.1k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2712
33.1k
    }
2713
28.3k
    max_lo += max_a0;
2714
28.3k
    max_hi += max_a1;
2715
2716
    // Compute the maximum value of our multiplication products and add to max_lo, max_hi
2717
98.9k
    for (size_t i = 0; i < num_multiplications; ++i) {
2718
70.5k
        const auto [product_lo, product_hi] = get_product_maximum(left[i], right[i]);
2719
70.5k
        max_lo += product_lo;
2720
70.5k
        max_hi += product_hi;
2721
70.5k
    }
2722
2723
28.3k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2724
28.3k
    max_hi += max_lo_carry;
2725
    // Compute the maximum number of bits in `max_lo` and `max_hi` - this defines the range constraint values we
2726
    // will need to apply to validate our product
2727
28.3k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2728
28.3k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2729
    // Turbo range checks only work for even bit ranges, so make sure these values are even
2730
    // TODO: This neccessary anymore? Turbo range checks now work with odd bit ranges...
2731
28.3k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2732
14.1k
        ++max_lo_bits;
2733
14.1k
    }
2734
28.3k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2735
14.2k
        ++max_hi_bits;
2736
14.2k
    }
2737
2738
28.3k
    if constexpr (HasPlookup<Builder>) {
2739
        // The plookup custom bigfield gate requires inputs are witnesses.
2740
        // If we're using constant values, instantiate them as circuit variables
2741
2742
28.3k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2743
28.3k
            bigfield output(input);
2744
28.3k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2745
28.3k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2746
28.3k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2747
28.3k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2748
28.3k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2749
28.3k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2750
28.3k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2751
28.3k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2752
28.3k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2753
28.3k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2754
28.3k
            output.context = ctx;
2755
28.3k
            return output;
2756
28.3k
        };
2757
2758
        // evalaute a nnf mul and add into existing lohi output for our extra product terms
2759
        // we need to add the result of (left_b * right_b) into lo_1_idx and hi_1_idx
2760
        // our custom gate evaluates: ((a * b) + (q * neg_modulus) - r) / 2^{136} = lo + hi * 2^{136}
2761
        // where q is a 'quotient' bigfield and neg_modulus is defined by selector polynomial values
2762
        // The custom gate costs 7 constraints, which is cheaper than computing `a * b` using multiplication +
2763
        // addition gates But....we want to obtain `left_a * right_b + lo_1 + hi_1 * 2^{136} = lo + hi * 2^{136}` If
2764
        // we set `neg_modulus = [2^{136}, 0, 0, 0]` and `q = [lo_1, 0, hi_1, 0]`, then we will add `lo_1` into
2765
        // `lo`, and `lo_1/2^{136} + hi_1` into `hi`. we can then subtract off `lo_1/2^{136}` from `hi`, by setting
2766
        // `r = [0, 0, lo_1, 0]` This saves us 2 addition gates as we don't have to add together the outputs of two
2767
        // calls to `evaluate_non_native_field_multiplication`
2768
28.3k
        std::vector<field_t<Builder>> limb_0_accumulator;
2769
28.3k
        std::vector<field_t<Builder>> limb_2_accumulator;
2770
28.3k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2771
2772
98.9k
        for (size_t i = 0; i < num_multiplications; ++i) {
2773
70.5k
            if (i == 0 && left[0].is_constant()) {
2774
0
                left[0] = convert_constant_to_fixed_witness(left[0]);
2775
0
            }
2776
70.5k
            if (i == 0 && right[0].is_constant()) {
2777
0
                right[0] = convert_constant_to_fixed_witness(right[0]);
2778
0
            }
2779
70.5k
            if (i > 0 && left[i].is_constant()) {
2780
0
                left[i] = convert_constant_to_fixed_witness(left[i]);
2781
0
            }
2782
70.5k
            if (i > 0 && right[i].is_constant()) {
2783
0
                right[i] = convert_constant_to_fixed_witness(right[i]);
2784
0
            }
2785
2786
70.5k
            if (i > 0) {
2787
42.1k
                bb::non_native_field_witnesses<bb::fr> mul_witnesses = {
2788
42.1k
                    {
2789
42.1k
                        left[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2790
42.1k
                        left[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2791
42.1k
                        left[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2792
42.1k
                        left[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2793
42.1k
                    },
2794
42.1k
                    {
2795
42.1k
                        right[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2796
42.1k
                        right[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2797
42.1k
                        right[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2798
42.1k
                        right[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2799
42.1k
                    },
2800
42.1k
                    {
2801
42.1k
                        ctx->zero_idx,
2802
42.1k
                        ctx->zero_idx,
2803
42.1k
                        ctx->zero_idx,
2804
42.1k
                        ctx->zero_idx,
2805
42.1k
                    },
2806
42.1k
                    {
2807
42.1k
                        ctx->zero_idx,
2808
42.1k
                        ctx->zero_idx,
2809
42.1k
                        ctx->zero_idx,
2810
42.1k
                        ctx->zero_idx,
2811
42.1k
                    },
2812
42.1k
                    { 0, 0, 0, 0 },
2813
42.1k
                    modulus,
2814
42.1k
                };
2815
2816
42.1k
                const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses);
2817
2818
42.1k
                field_t<Builder> lo_2 = field_t<Builder>::from_witness_index(ctx, lo_2_idx);
2819
42.1k
                field_t<Builder> hi_2 = field_t<Builder>::from_witness_index(ctx, hi_2_idx);
2820
2821
42.1k
                limb_0_accumulator.emplace_back(-lo_2);
2822
42.1k
                limb_2_accumulator.emplace_back(-hi_2);
2823
42.1k
                prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
2824
42.1k
            }
2825
70.5k
        }
2826
28.3k
        if (quotient.is_constant()) {
2827
0
            quotient = convert_constant_to_fixed_witness(quotient);
2828
0
        }
2829
2830
28.3k
        bool no_remainders = remainders.size() == 0;
2831
28.3k
        if (!no_remainders) {
2832
28.3k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
2833
28.3k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
2834
28.3k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
2835
28.3k
        }
2836
28.3k
        for (size_t i = 1; i < remainders.size(); ++i) {
2837
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2838
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2839
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2840
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2841
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2842
0
        }
2843
33.1k
        for (const auto& add : to_add) {
2844
33.1k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2845
33.1k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2846
33.1k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2847
33.1k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2848
33.1k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2849
33.1k
        }
2850
2851
28.3k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
2852
28.3k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
2853
28.3k
        if (accumulated_lo.is_constant()) {
2854
0
            accumulated_lo =
2855
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
2856
0
        }
2857
28.3k
        if (accumulated_hi.is_constant()) {
2858
0
            accumulated_hi =
2859
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
2860
0
        }
2861
28.3k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2862
28.3k
                                                    : remainders[0].binary_basis_limbs[1].element;
2863
28.3k
        if (remainder1.is_constant()) {
2864
0
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
2865
0
        }
2866
28.3k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2867
28.3k
                                                    : remainders[0].binary_basis_limbs[3].element;
2868
28.3k
        if (remainder3.is_constant()) {
2869
0
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
2870
0
        }
2871
28.3k
        field_t<Builder> remainder_limbs[4]{
2872
28.3k
            accumulated_lo,
2873
28.3k
            remainder1,
2874
28.3k
            accumulated_hi,
2875
28.3k
            remainder3,
2876
28.3k
        };
2877
28.3k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2878
2879
28.3k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2880
28.3k
            {
2881
28.3k
                left[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2882
28.3k
                left[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2883
28.3k
                left[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2884
28.3k
                left[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2885
28.3k
            },
2886
28.3k
            {
2887
28.3k
                right[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2888
28.3k
                right[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2889
28.3k
                right[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2890
28.3k
                right[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2891
28.3k
            },
2892
28.3k
            {
2893
28.3k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2894
28.3k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2895
28.3k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2896
28.3k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2897
28.3k
            },
2898
28.3k
            {
2899
28.3k
                remainder_limbs[0].get_normalized_witness_index(),
2900
28.3k
                remainder_limbs[1].get_normalized_witness_index(),
2901
28.3k
                remainder_limbs[2].get_normalized_witness_index(),
2902
28.3k
                remainder_limbs[3].get_normalized_witness_index(),
2903
28.3k
            },
2904
28.3k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2905
28.3k
            modulus,
2906
28.3k
        };
2907
2908
28.3k
        const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2909
2910
28.3k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2911
2912
28.3k
        field_t<Builder>::evaluate_polynomial_identity(left[0].prime_basis_limb,
2913
28.3k
                                                       right[0].prime_basis_limb,
2914
28.3k
                                                       quotient.prime_basis_limb * neg_prime,
2915
28.3k
                                                       -remainder_prime_limb);
2916
2917
28.3k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_1_idx) + borrow_lo;
2918
28.3k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_1_idx);
2919
2920
28.3k
        uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2921
28.3k
        uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2922
2923
28.3k
        if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2924
0
            carry_lo_msb = 0;
2925
0
        }
2926
28.3k
        if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2927
0
            carry_hi_msb = 0;
2928
0
        }
2929
2930
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2931
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2932
28.3k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2933
0
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2934
0
                                           lo.get_normalized_witness_index(),
2935
0
                                           (size_t)carry_hi_msb,
2936
0
                                           (size_t)carry_lo_msb);
2937
28.3k
        } else {
2938
28.3k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2939
28.3k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2940
28.3k
        }
2941
        /*  NOTE TO AUDITOR: An extraneous block
2942
               if constexpr (HasPlookup<Builder>) {
2943
                   carry_lo = carry_lo.normalize();
2944
                   carry_hi = carry_hi.normalize();
2945
                   ctx->decompose_into_default_range(carry_lo.witness_index, static_cast<size_t>(carry_lo_msb));
2946
                   ctx->decompose_into_default_range(carry_hi.witness_index, static_cast<size_t>(carry_hi_msb));
2947
               }
2948
            was removed from the `else` block below. See  the conversation at
2949
               https://github.com/AztecProtocol/aztec2-internal/pull/1023
2950
            We should make sure that no constraint like this is needed but missing (e.g., an equivalent constraint
2951
            was just imposed?). */
2952
28.3k
    } else {
2953
28.3k
        field_t b0 = left[0].binary_basis_limbs[1].element.madd(
2954
28.3k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2955
28.3k
        field_t b1 = left[0].binary_basis_limbs[0].element.madd(
2956
28.3k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2957
28.3k
        field_t c0 = left[0].binary_basis_limbs[1].element.madd(
2958
28.3k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2959
28.3k
        field_t c1 = left[0].binary_basis_limbs[2].element.madd(
2960
28.3k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2961
28.3k
        field_t c2 = left[0].binary_basis_limbs[0].element.madd(
2962
28.3k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2963
28.3k
        field_t d0 = left[0].binary_basis_limbs[3].element.madd(
2964
28.3k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2965
28.3k
        field_t d1 = left[0].binary_basis_limbs[2].element.madd(
2966
28.3k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2967
28.3k
        field_t d2 = left[0].binary_basis_limbs[1].element.madd(
2968
28.3k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2969
28.3k
        field_t d3 = left[0].binary_basis_limbs[0].element.madd(
2970
28.3k
            right[0].binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2971
2972
        /**
2973
         * Compute "limb accumulators"
2974
         * `limb_0_accumulator` contains contributions in the range 0 - 2^{3t}
2975
         * `limb_2_accumulator` contains contributiosn in the range 2^{2t} - 2^{5t} (t = MAX_NUM_LIMB_BITS)
2976
         * Actual range will vary a few bits because of lazy reduction techniques
2977
         *
2978
         * We store these values in an "accumulator" vector in order to efficiently add them into a sum.
2979
         * i.e. limb_0 =- field_t::accumulate(limb_0_accumulator)
2980
         * This costs us fewer gates than addition operations because we can add 2 values into a sum in a single
2981
         * custom gate.
2982
         **/
2983
2984
28.3k
        std::vector<field_t<Builder>> limb_0_accumulator;
2985
28.3k
        std::vector<field_t<Builder>> limb_2_accumulator;
2986
28.3k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2987
2988
        // Add remaining products into the limb accumulators.
2989
        // We negate the product values because the accumulator values itself will be negated
2990
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
2991
        // that the accumulators originaly tracked the remainder term (which is negated)
2992
2993
28.3k
        for (size_t i = 1; i < num_multiplications; ++i) {
2994
28.3k
            field_t lo_2 = left[i].binary_basis_limbs[0].element * right[i].binary_basis_limbs[0].element;
2995
28.3k
            lo_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[0].element * shift_1, lo_2);
2996
28.3k
            lo_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[1].element * shift_1, lo_2);
2997
28.3k
            field_t hi_2 = left[i].binary_basis_limbs[1].element * right[i].binary_basis_limbs[1].element;
2998
28.3k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[0].element, hi_2);
2999
28.3k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[2].element, hi_2);
3000
28.3k
            hi_2 = left[i].binary_basis_limbs[3].element.madd(right[i].binary_basis_limbs[0].element * shift_1, hi_2);
3001
28.3k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[1].element * shift_1, hi_2);
3002
28.3k
            hi_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[2].element * shift_1, hi_2);
3003
28.3k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[3].element * shift_1, hi_2);
3004
3005
28.3k
            limb_0_accumulator.emplace_back(-lo_2);
3006
28.3k
            limb_2_accumulator.emplace_back(-hi_2);
3007
28.3k
            prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
3008
28.3k
        }
3009
        // add cached products into the limb accumulators.
3010
        // We negate the cache values because the accumulator values itself will be negated
3011
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
3012
        // that the accumulators originaly tracked the remainder term (which is negated)
3013
3014
        // Update the accumulators with the remainder terms. First check we actually have remainder terms!
3015
        //(not present when we're checking a product is 0 mod p). See `assert_is_in_field`
3016
3017
28.3k
        bool no_remainders = remainders.size() == 0;
3018
28.3k
        if (!no_remainders) {
3019
28.3k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
3020
28.3k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
3021
28.3k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
3022
28.3k
        }
3023
28.3k
        for (size_t i = 1; i < remainders.size(); ++i) {
3024
28.3k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
3025
28.3k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
3026
28.3k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
3027
28.3k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
3028
28.3k
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
3029
28.3k
        }
3030
28.3k
        for (const auto& add : to_add) {
3031
28.3k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
3032
28.3k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
3033
28.3k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
3034
28.3k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
3035
28.3k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
3036
28.3k
        }
3037
3038
28.3k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
3039
28.3k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
3040
28.3k
        if (accumulated_lo.is_constant()) {
3041
28.3k
            accumulated_lo =
3042
28.3k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
3043
28.3k
        }
3044
28.3k
        if (accumulated_hi.is_constant()) {
3045
28.3k
            accumulated_hi =
3046
28.3k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
3047
28.3k
        }
3048
28.3k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3049
28.3k
                                                    : remainders[0].binary_basis_limbs[1].element;
3050
28.3k
        if (remainder1.is_constant()) {
3051
28.3k
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
3052
28.3k
        }
3053
28.3k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3054
28.3k
                                                    : remainders[0].binary_basis_limbs[3].element;
3055
28.3k
        if (remainder3.is_constant()) {
3056
28.3k
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
3057
28.3k
        }
3058
28.3k
        field_t<Builder> remainder_limbs[4]{
3059
28.3k
            accumulated_lo,
3060
28.3k
            remainder1,
3061
28.3k
            accumulated_hi,
3062
28.3k
            remainder3,
3063
28.3k
        };
3064
28.3k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
3065
3066
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
3067
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
3068
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
3069
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
3070
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
3071
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
3072
3073
28.3k
        field_t r0 = left[0].binary_basis_limbs[0].element.madd(
3074
28.3k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3075
28.3k
        field_t r1 = b0.add_two(b1, -remainder_limbs[1]);
3076
28.3k
        const field_t r2 = c0.add_two(c1, c2);
3077
28.3k
        const field_t r3 = d0 + d1.add_two(d2, d3);
3078
3079
28.3k
        field_t carry_lo_0 = r0 * shift_right_2;
3080
28.3k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3081
28.3k
        field_t carry_lo_2 = -(remainder_limbs[0] * shift_right_2);
3082
28.3k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3083
3084
28.3k
        field_t t1 = carry_lo.add_two(-remainder_limbs[2], -(remainder_limbs[3] * shift_1));
3085
28.3k
        carry_lo += borrow_lo;
3086
28.3k
        field_t carry_hi_0 = r2 * shift_right_2;
3087
28.3k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3088
28.3k
        field_t carry_hi_2 = t1 * shift_right_2;
3089
28.3k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3090
3091
28.3k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3092
3093
28.3k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
3094
3095
28.3k
        linear_terms += -remainder_prime_limb;
3096
3097
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
3098
28.3k
        field_t<Builder>::evaluate_polynomial_identity(
3099
28.3k
            left[0].prime_basis_limb, right[0].prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3100
3101
28.3k
        const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3102
28.3k
        const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3103
3104
28.3k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3105
3106
28.3k
        if constexpr (HasPlookup<Builder>) {
3107
28.3k
            carry_lo = carry_lo.normalize();
3108
28.3k
            carry_hi = carry_hi.normalize();
3109
28.3k
            ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(),
3110
28.3k
                                              static_cast<size_t>(carry_lo_msb));
3111
28.3k
            ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(),
3112
28.3k
                                              static_cast<size_t>(carry_hi_msb));
3113
3114
28.3k
        } else {
3115
28.3k
            if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3116
28.3k
                field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3117
28.3k
                carry_combined = carry_combined.normalize();
3118
28.3k
                const auto accumulators = ctx->decompose_into_base4_accumulators(
3119
28.3k
                    carry_combined.get_normalized_witness_index(),
3120
28.3k
                    static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3121
28.3k
                    "bigfield: carry_combined too large in unsafe_evaluate_multiple_multiply_add.");
3122
28.3k
                field_t<Builder> accumulator_midpoint = field_t<Builder>::from_witness_index(
3123
28.3k
                    ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3124
28.3k
                carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3125
28.3k
            } else {
3126
28.3k
                carry_lo = carry_lo.normalize();
3127
28.3k
                carry_hi = carry_hi.normalize();
3128
28.3k
                ctx->decompose_into_base4_accumulators(
3129
28.3k
                    carry_lo.get_normalized_witness_index(),
3130
28.3k
                    static_cast<size_t>(carry_lo_msb),
3131
28.3k
                    "bigfield: carry_lo too large in unsafe_evaluate_multiple_multiply_add.");
3132
28.3k
                ctx->decompose_into_base4_accumulators(
3133
28.3k
                    carry_hi.get_normalized_witness_index(),
3134
28.3k
                    static_cast<size_t>(carry_hi_msb),
3135
28.3k
                    "bigfield: carry_hi too large in unsafe_evaluate_multiple_multiply_add.");
3136
28.3k
            }
3137
28.3k
        }
3138
28.3k
    }
3139
28.3k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_
Line
Count
Source
2608
2.23k
{
2609
2.23k
    ASSERT(input_left.size() == input_right.size());
2610
2.23k
    ASSERT(input_left.size() <= MAXIMUM_SUMMAND_COUNT);
2611
2.23k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
2612
2.23k
    ASSERT(input_remainders.size() <= MAXIMUM_SUMMAND_COUNT);
2613
2614
2.23k
    ASSERT(input_left.size() == input_right.size() && input_left.size() < 1024);
2615
    // Sanity checks
2616
7.01k
    for (auto& el : input_left) {
2617
7.01k
        el.sanity_check();
2618
7.01k
    }
2619
7.01k
    for (auto& el : input_right) {
2620
7.01k
        el.sanity_check();
2621
7.01k
    }
2622
3.19k
    for (auto& el : to_add) {
2623
3.19k
        el.sanity_check();
2624
3.19k
    }
2625
2.23k
    input_quotient.sanity_check();
2626
2.23k
    for (auto& el : input_remainders) {
2627
2.23k
        el.sanity_check();
2628
2.23k
    }
2629
2.23k
    std::vector<bigfield> remainders(input_remainders);
2630
2.23k
    std::vector<bigfield> left(input_left);
2631
2.23k
    std::vector<bigfield> right(input_right);
2632
2.23k
    bigfield quotient = input_quotient;
2633
2.23k
    const size_t num_multiplications = input_left.size();
2634
2635
2.23k
    Builder* ctx = input_left[0].context ? input_left[0].context : input_right[0].context;
2636
2637
2.23k
    const auto get_product_maximum = [](const bigfield& left, const bigfield& right) {
2638
2.23k
        uint512_t max_b0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[0].maximum_value);
2639
2.23k
        uint512_t max_b1_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[1].maximum_value);
2640
2.23k
        uint512_t max_c0_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[1].maximum_value);
2641
2.23k
        uint512_t max_c1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[0].maximum_value);
2642
2.23k
        uint512_t max_c2_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[2].maximum_value);
2643
2.23k
        uint512_t max_d0_inner = (left.binary_basis_limbs[3].maximum_value * right.binary_basis_limbs[0].maximum_value);
2644
2.23k
        uint512_t max_d1_inner = (left.binary_basis_limbs[2].maximum_value * right.binary_basis_limbs[1].maximum_value);
2645
2.23k
        uint512_t max_d2_inner = (left.binary_basis_limbs[1].maximum_value * right.binary_basis_limbs[2].maximum_value);
2646
2.23k
        uint512_t max_d3_inner = (left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[3].maximum_value);
2647
2.23k
        uint512_t max_r0_inner = left.binary_basis_limbs[0].maximum_value * right.binary_basis_limbs[0].maximum_value;
2648
2649
2.23k
        const uint512_t max_r1_inner = max_b0_inner + max_b1_inner;
2650
2.23k
        const uint512_t max_r2_inner = max_c0_inner + max_c1_inner + max_c2_inner;
2651
2.23k
        const uint512_t max_r3_inner = max_d0_inner + max_d1_inner + max_d2_inner + max_d3_inner;
2652
2.23k
        const uint512_t max_lo_temp = max_r0_inner + (max_r1_inner << NUM_LIMB_BITS);
2653
2.23k
        const uint512_t max_hi_temp = max_r2_inner + (max_r3_inner << NUM_LIMB_BITS);
2654
2.23k
        return std::pair<uint512_t, uint512_t>(max_lo_temp, max_hi_temp);
2655
2.23k
    };
2656
2657
    /**
2658
     * Step 1: Compute the maximum potential value of our product limbs
2659
     *
2660
     * max_lo = maximum value of limb products that span the range 0 - 2^{3t}
2661
     * max_hi = maximum value of limb products that span the range 2^{2t} - 2^{5t}
2662
     * (t = NUM_LIMB_BITS)
2663
     **/
2664
2.23k
    uint512_t max_lo = 0;
2665
2.23k
    uint512_t max_hi = 0;
2666
2667
    // Compute max values of quotient product limb products
2668
2.23k
    uint512_t max_b0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[0].maximum_value);
2669
2.23k
    uint512_t max_b1 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[1].maximum_value);
2670
2.23k
    uint512_t max_c0 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[1].maximum_value);
2671
2.23k
    uint512_t max_c1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[0].maximum_value);
2672
2.23k
    uint512_t max_c2 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[2].maximum_value);
2673
2.23k
    uint512_t max_d0 = (neg_modulus_limbs_u256[3] * quotient.binary_basis_limbs[0].maximum_value);
2674
2.23k
    uint512_t max_d1 = (neg_modulus_limbs_u256[2] * quotient.binary_basis_limbs[1].maximum_value);
2675
2.23k
    uint512_t max_d2 = (neg_modulus_limbs_u256[1] * quotient.binary_basis_limbs[2].maximum_value);
2676
2.23k
    uint512_t max_d3 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[3].maximum_value);
2677
2678
    // max_r0 = terms from 0 - 2^2t
2679
    // max_r1 = terms from 2^t - 2^3t
2680
    // max_r2 = terms from 2^2t - 2^4t
2681
    // max_r3 = terms from 2^3t - 2^5t
2682
2.23k
    uint512_t max_r0 = (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2683
2.23k
    max_r0 += (neg_modulus_limbs_u256[0] * quotient.binary_basis_limbs[0].maximum_value);
2684
2.23k
    uint512_t max_r1 = max_b0 + max_b1;
2685
2686
2.23k
    uint256_t borrow_lo_value(0);
2687
2.23k
    for (const auto& remainder : input_remainders) {
2688
2.23k
        max_r0 += remainder.binary_basis_limbs[0].maximum_value;
2689
2.23k
        max_r1 += remainder.binary_basis_limbs[1].maximum_value;
2690
2691
2.23k
        borrow_lo_value += remainder.binary_basis_limbs[0].maximum_value +
2692
2.23k
                           (remainder.binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2693
2.23k
    }
2694
2.23k
    borrow_lo_value >>= 2 * NUM_LIMB_BITS;
2695
2.23k
    field_t<Builder> borrow_lo(ctx, bb::fr(borrow_lo_value));
2696
2697
2.23k
    const uint512_t max_r2 = max_c0 + max_c1 + max_c2;
2698
2.23k
    const uint512_t max_r3 = max_d0 + max_d1 + max_d2 + max_d3;
2699
2700
    // update max_lo, max_hi with quotient limb product terms.
2701
2.23k
    max_lo += max_r0 + (max_r1 << NUM_LIMB_BITS);
2702
2.23k
    max_hi += max_r2 + (max_r3 << NUM_LIMB_BITS);
2703
2704
    // Compute maximum value of addition terms in `to_add` and add to max_lo, max_hi
2705
2.23k
    uint512_t max_a0(0);
2706
2.23k
    uint512_t max_a1(0);
2707
5.42k
    for (size_t i = 0; i < to_add.size(); ++i) {
2708
3.19k
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
2709
3.19k
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
2710
3.19k
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
2711
3.19k
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
2712
3.19k
    }
2713
2.23k
    max_lo += max_a0;
2714
2.23k
    max_hi += max_a1;
2715
2716
    // Compute the maximum value of our multiplication products and add to max_lo, max_hi
2717
9.24k
    for (size_t i = 0; i < num_multiplications; ++i) {
2718
7.01k
        const auto [product_lo, product_hi] = get_product_maximum(left[i], right[i]);
2719
7.01k
        max_lo += product_lo;
2720
7.01k
        max_hi += product_hi;
2721
7.01k
    }
2722
2723
2.23k
    const uint512_t max_lo_carry = max_lo >> (2 * NUM_LIMB_BITS);
2724
2.23k
    max_hi += max_lo_carry;
2725
    // Compute the maximum number of bits in `max_lo` and `max_hi` - this defines the range constraint values we
2726
    // will need to apply to validate our product
2727
2.23k
    uint64_t max_lo_bits = (max_lo.get_msb() + 1);
2728
2.23k
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
2729
    // Turbo range checks only work for even bit ranges, so make sure these values are even
2730
    // TODO: This neccessary anymore? Turbo range checks now work with odd bit ranges...
2731
2.23k
    if ((max_lo_bits & 1ULL) == 1ULL) {
2732
1.59k
        ++max_lo_bits;
2733
1.59k
    }
2734
2.23k
    if ((max_hi_bits & 1ULL) == 1ULL) {
2735
1.59k
        ++max_hi_bits;
2736
1.59k
    }
2737
2738
2.23k
    if constexpr (HasPlookup<Builder>) {
2739
        // The plookup custom bigfield gate requires inputs are witnesses.
2740
        // If we're using constant values, instantiate them as circuit variables
2741
2742
2.23k
        const auto convert_constant_to_fixed_witness = [ctx](const bigfield& input) {
2743
2.23k
            bigfield output(input);
2744
2.23k
            output.prime_basis_limb = field_t<Builder>::from_witness_index(
2745
2.23k
                ctx, ctx->put_constant_variable(input.prime_basis_limb.get_value()));
2746
2.23k
            output.binary_basis_limbs[0].element = field_t<Builder>::from_witness_index(
2747
2.23k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[0].element.get_value()));
2748
2.23k
            output.binary_basis_limbs[1].element = field_t<Builder>::from_witness_index(
2749
2.23k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[1].element.get_value()));
2750
2.23k
            output.binary_basis_limbs[2].element = field_t<Builder>::from_witness_index(
2751
2.23k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[2].element.get_value()));
2752
2.23k
            output.binary_basis_limbs[3].element = field_t<Builder>::from_witness_index(
2753
2.23k
                ctx, ctx->put_constant_variable(input.binary_basis_limbs[3].element.get_value()));
2754
2.23k
            output.context = ctx;
2755
2.23k
            return output;
2756
2.23k
        };
2757
2758
        // evalaute a nnf mul and add into existing lohi output for our extra product terms
2759
        // we need to add the result of (left_b * right_b) into lo_1_idx and hi_1_idx
2760
        // our custom gate evaluates: ((a * b) + (q * neg_modulus) - r) / 2^{136} = lo + hi * 2^{136}
2761
        // where q is a 'quotient' bigfield and neg_modulus is defined by selector polynomial values
2762
        // The custom gate costs 7 constraints, which is cheaper than computing `a * b` using multiplication +
2763
        // addition gates But....we want to obtain `left_a * right_b + lo_1 + hi_1 * 2^{136} = lo + hi * 2^{136}` If
2764
        // we set `neg_modulus = [2^{136}, 0, 0, 0]` and `q = [lo_1, 0, hi_1, 0]`, then we will add `lo_1` into
2765
        // `lo`, and `lo_1/2^{136} + hi_1` into `hi`. we can then subtract off `lo_1/2^{136}` from `hi`, by setting
2766
        // `r = [0, 0, lo_1, 0]` This saves us 2 addition gates as we don't have to add together the outputs of two
2767
        // calls to `evaluate_non_native_field_multiplication`
2768
2.23k
        std::vector<field_t<Builder>> limb_0_accumulator;
2769
2.23k
        std::vector<field_t<Builder>> limb_2_accumulator;
2770
2.23k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2771
2772
9.24k
        for (size_t i = 0; i < num_multiplications; ++i) {
2773
7.01k
            if (i == 0 && left[0].is_constant()) {
2774
0
                left[0] = convert_constant_to_fixed_witness(left[0]);
2775
0
            }
2776
7.01k
            if (i == 0 && right[0].is_constant()) {
2777
0
                right[0] = convert_constant_to_fixed_witness(right[0]);
2778
0
            }
2779
7.01k
            if (i > 0 && left[i].is_constant()) {
2780
0
                left[i] = convert_constant_to_fixed_witness(left[i]);
2781
0
            }
2782
7.01k
            if (i > 0 && right[i].is_constant()) {
2783
4
                right[i] = convert_constant_to_fixed_witness(right[i]);
2784
4
            }
2785
2786
7.01k
            if (i > 0) {
2787
4.77k
                bb::non_native_field_witnesses<bb::fr> mul_witnesses = {
2788
4.77k
                    {
2789
4.77k
                        left[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2790
4.77k
                        left[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2791
4.77k
                        left[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2792
4.77k
                        left[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2793
4.77k
                    },
2794
4.77k
                    {
2795
4.77k
                        right[i].binary_basis_limbs[0].element.get_normalized_witness_index(),
2796
4.77k
                        right[i].binary_basis_limbs[1].element.get_normalized_witness_index(),
2797
4.77k
                        right[i].binary_basis_limbs[2].element.get_normalized_witness_index(),
2798
4.77k
                        right[i].binary_basis_limbs[3].element.get_normalized_witness_index(),
2799
4.77k
                    },
2800
4.77k
                    {
2801
4.77k
                        ctx->zero_idx,
2802
4.77k
                        ctx->zero_idx,
2803
4.77k
                        ctx->zero_idx,
2804
4.77k
                        ctx->zero_idx,
2805
4.77k
                    },
2806
4.77k
                    {
2807
4.77k
                        ctx->zero_idx,
2808
4.77k
                        ctx->zero_idx,
2809
4.77k
                        ctx->zero_idx,
2810
4.77k
                        ctx->zero_idx,
2811
4.77k
                    },
2812
4.77k
                    { 0, 0, 0, 0 },
2813
4.77k
                    modulus,
2814
4.77k
                };
2815
2816
4.77k
                const auto [lo_2_idx, hi_2_idx] = ctx->queue_partial_non_native_field_multiplication(mul_witnesses);
2817
2818
4.77k
                field_t<Builder> lo_2 = field_t<Builder>::from_witness_index(ctx, lo_2_idx);
2819
4.77k
                field_t<Builder> hi_2 = field_t<Builder>::from_witness_index(ctx, hi_2_idx);
2820
2821
4.77k
                limb_0_accumulator.emplace_back(-lo_2);
2822
4.77k
                limb_2_accumulator.emplace_back(-hi_2);
2823
4.77k
                prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
2824
4.77k
            }
2825
7.01k
        }
2826
2.23k
        if (quotient.is_constant()) {
2827
0
            quotient = convert_constant_to_fixed_witness(quotient);
2828
0
        }
2829
2830
2.23k
        bool no_remainders = remainders.size() == 0;
2831
2.23k
        if (!no_remainders) {
2832
2.23k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
2833
2.23k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
2834
2.23k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
2835
2.23k
        }
2836
2.23k
        for (size_t i = 1; i < remainders.size(); ++i) {
2837
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
2838
0
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
2839
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
2840
0
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
2841
0
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
2842
0
        }
2843
3.19k
        for (const auto& add : to_add) {
2844
3.19k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
2845
3.19k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
2846
3.19k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
2847
3.19k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
2848
3.19k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
2849
3.19k
        }
2850
2851
2.23k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
2852
2.23k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
2853
2.23k
        if (accumulated_lo.is_constant()) {
2854
0
            accumulated_lo =
2855
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
2856
0
        }
2857
2.23k
        if (accumulated_hi.is_constant()) {
2858
0
            accumulated_hi =
2859
0
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
2860
0
        }
2861
2.23k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2862
2.23k
                                                    : remainders[0].binary_basis_limbs[1].element;
2863
2.23k
        if (remainder1.is_constant()) {
2864
0
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
2865
0
        }
2866
2.23k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
2867
2.23k
                                                    : remainders[0].binary_basis_limbs[3].element;
2868
2.23k
        if (remainder3.is_constant()) {
2869
0
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
2870
0
        }
2871
2.23k
        field_t<Builder> remainder_limbs[4]{
2872
2.23k
            accumulated_lo,
2873
2.23k
            remainder1,
2874
2.23k
            accumulated_hi,
2875
2.23k
            remainder3,
2876
2.23k
        };
2877
2.23k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
2878
2879
2.23k
        bb::non_native_field_witnesses<bb::fr> witnesses{
2880
2.23k
            {
2881
2.23k
                left[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2882
2.23k
                left[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2883
2.23k
                left[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2884
2.23k
                left[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2885
2.23k
            },
2886
2.23k
            {
2887
2.23k
                right[0].binary_basis_limbs[0].element.get_normalized_witness_index(),
2888
2.23k
                right[0].binary_basis_limbs[1].element.get_normalized_witness_index(),
2889
2.23k
                right[0].binary_basis_limbs[2].element.get_normalized_witness_index(),
2890
2.23k
                right[0].binary_basis_limbs[3].element.get_normalized_witness_index(),
2891
2.23k
            },
2892
2.23k
            {
2893
2.23k
                quotient.binary_basis_limbs[0].element.get_normalized_witness_index(),
2894
2.23k
                quotient.binary_basis_limbs[1].element.get_normalized_witness_index(),
2895
2.23k
                quotient.binary_basis_limbs[2].element.get_normalized_witness_index(),
2896
2.23k
                quotient.binary_basis_limbs[3].element.get_normalized_witness_index(),
2897
2.23k
            },
2898
2.23k
            {
2899
2.23k
                remainder_limbs[0].get_normalized_witness_index(),
2900
2.23k
                remainder_limbs[1].get_normalized_witness_index(),
2901
2.23k
                remainder_limbs[2].get_normalized_witness_index(),
2902
2.23k
                remainder_limbs[3].get_normalized_witness_index(),
2903
2.23k
            },
2904
2.23k
            { neg_modulus_limbs[0], neg_modulus_limbs[1], neg_modulus_limbs[2], neg_modulus_limbs[3] },
2905
2.23k
            modulus,
2906
2.23k
        };
2907
2908
2.23k
        const auto [lo_1_idx, hi_1_idx] = ctx->evaluate_non_native_field_multiplication(witnesses);
2909
2910
2.23k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
2911
2912
2.23k
        field_t<Builder>::evaluate_polynomial_identity(left[0].prime_basis_limb,
2913
2.23k
                                                       right[0].prime_basis_limb,
2914
2.23k
                                                       quotient.prime_basis_limb * neg_prime,
2915
2.23k
                                                       -remainder_prime_limb);
2916
2917
2.23k
        field_t lo = field_t<Builder>::from_witness_index(ctx, lo_1_idx) + borrow_lo;
2918
2.23k
        field_t hi = field_t<Builder>::from_witness_index(ctx, hi_1_idx);
2919
2920
2.23k
        uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
2921
2.23k
        uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
2922
2923
2.23k
        if (max_lo_bits < (2 * NUM_LIMB_BITS)) {
2924
0
            carry_lo_msb = 0;
2925
0
        }
2926
2.23k
        if (max_hi_bits < (2 * NUM_LIMB_BITS)) {
2927
0
            carry_hi_msb = 0;
2928
0
        }
2929
2930
        // if both the hi and lo output limbs have less than 70 bits, we can use our custom
2931
        // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates)
2932
2.23k
        if (carry_lo_msb <= 70 && carry_hi_msb <= 70) {
2933
0
            ctx->range_constrain_two_limbs(hi.get_normalized_witness_index(),
2934
0
                                           lo.get_normalized_witness_index(),
2935
0
                                           (size_t)carry_hi_msb,
2936
0
                                           (size_t)carry_lo_msb);
2937
2.23k
        } else {
2938
2.23k
            ctx->decompose_into_default_range(hi.get_normalized_witness_index(), carry_hi_msb);
2939
2.23k
            ctx->decompose_into_default_range(lo.get_normalized_witness_index(), carry_lo_msb);
2940
2.23k
        }
2941
        /*  NOTE TO AUDITOR: An extraneous block
2942
               if constexpr (HasPlookup<Builder>) {
2943
                   carry_lo = carry_lo.normalize();
2944
                   carry_hi = carry_hi.normalize();
2945
                   ctx->decompose_into_default_range(carry_lo.witness_index, static_cast<size_t>(carry_lo_msb));
2946
                   ctx->decompose_into_default_range(carry_hi.witness_index, static_cast<size_t>(carry_hi_msb));
2947
               }
2948
            was removed from the `else` block below. See  the conversation at
2949
               https://github.com/AztecProtocol/aztec2-internal/pull/1023
2950
            We should make sure that no constraint like this is needed but missing (e.g., an equivalent constraint
2951
            was just imposed?). */
2952
2.23k
    } else {
2953
2.23k
        field_t b0 = left[0].binary_basis_limbs[1].element.madd(
2954
2.23k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
2955
2.23k
        field_t b1 = left[0].binary_basis_limbs[0].element.madd(
2956
2.23k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
2957
2.23k
        field_t c0 = left[0].binary_basis_limbs[1].element.madd(
2958
2.23k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
2959
2.23k
        field_t c1 = left[0].binary_basis_limbs[2].element.madd(
2960
2.23k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
2961
2.23k
        field_t c2 = left[0].binary_basis_limbs[0].element.madd(
2962
2.23k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
2963
2.23k
        field_t d0 = left[0].binary_basis_limbs[3].element.madd(
2964
2.23k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
2965
2.23k
        field_t d1 = left[0].binary_basis_limbs[2].element.madd(
2966
2.23k
            right[0].binary_basis_limbs[1].element, quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
2967
2.23k
        field_t d2 = left[0].binary_basis_limbs[1].element.madd(
2968
2.23k
            right[0].binary_basis_limbs[2].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
2969
2.23k
        field_t d3 = left[0].binary_basis_limbs[0].element.madd(
2970
2.23k
            right[0].binary_basis_limbs[3].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
2971
2972
        /**
2973
         * Compute "limb accumulators"
2974
         * `limb_0_accumulator` contains contributions in the range 0 - 2^{3t}
2975
         * `limb_2_accumulator` contains contributiosn in the range 2^{2t} - 2^{5t} (t = MAX_NUM_LIMB_BITS)
2976
         * Actual range will vary a few bits because of lazy reduction techniques
2977
         *
2978
         * We store these values in an "accumulator" vector in order to efficiently add them into a sum.
2979
         * i.e. limb_0 =- field_t::accumulate(limb_0_accumulator)
2980
         * This costs us fewer gates than addition operations because we can add 2 values into a sum in a single
2981
         * custom gate.
2982
         **/
2983
2984
2.23k
        std::vector<field_t<Builder>> limb_0_accumulator;
2985
2.23k
        std::vector<field_t<Builder>> limb_2_accumulator;
2986
2.23k
        std::vector<field_t<Builder>> prime_limb_accumulator;
2987
2988
        // Add remaining products into the limb accumulators.
2989
        // We negate the product values because the accumulator values itself will be negated
2990
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
2991
        // that the accumulators originaly tracked the remainder term (which is negated)
2992
2993
2.23k
        for (size_t i = 1; i < num_multiplications; ++i) {
2994
2.23k
            field_t lo_2 = left[i].binary_basis_limbs[0].element * right[i].binary_basis_limbs[0].element;
2995
2.23k
            lo_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[0].element * shift_1, lo_2);
2996
2.23k
            lo_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[1].element * shift_1, lo_2);
2997
2.23k
            field_t hi_2 = left[i].binary_basis_limbs[1].element * right[i].binary_basis_limbs[1].element;
2998
2.23k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[0].element, hi_2);
2999
2.23k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[2].element, hi_2);
3000
2.23k
            hi_2 = left[i].binary_basis_limbs[3].element.madd(right[i].binary_basis_limbs[0].element * shift_1, hi_2);
3001
2.23k
            hi_2 = left[i].binary_basis_limbs[2].element.madd(right[i].binary_basis_limbs[1].element * shift_1, hi_2);
3002
2.23k
            hi_2 = left[i].binary_basis_limbs[1].element.madd(right[i].binary_basis_limbs[2].element * shift_1, hi_2);
3003
2.23k
            hi_2 = left[i].binary_basis_limbs[0].element.madd(right[i].binary_basis_limbs[3].element * shift_1, hi_2);
3004
3005
2.23k
            limb_0_accumulator.emplace_back(-lo_2);
3006
2.23k
            limb_2_accumulator.emplace_back(-hi_2);
3007
2.23k
            prime_limb_accumulator.emplace_back(-(left[i].prime_basis_limb * right[i].prime_basis_limb));
3008
2.23k
        }
3009
        // add cached products into the limb accumulators.
3010
        // We negate the cache values because the accumulator values itself will be negated
3011
        // TODO: why do we do this double negation exactly? seems a bit pointless. I think it stems from the fact
3012
        // that the accumulators originaly tracked the remainder term (which is negated)
3013
3014
        // Update the accumulators with the remainder terms. First check we actually have remainder terms!
3015
        //(not present when we're checking a product is 0 mod p). See `assert_is_in_field`
3016
3017
2.23k
        bool no_remainders = remainders.size() == 0;
3018
2.23k
        if (!no_remainders) {
3019
2.23k
            limb_0_accumulator.emplace_back(remainders[0].binary_basis_limbs[0].element);
3020
2.23k
            limb_2_accumulator.emplace_back(remainders[0].binary_basis_limbs[2].element);
3021
2.23k
            prime_limb_accumulator.emplace_back(remainders[0].prime_basis_limb);
3022
2.23k
        }
3023
2.23k
        for (size_t i = 1; i < remainders.size(); ++i) {
3024
2.23k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[0].element);
3025
2.23k
            limb_0_accumulator.emplace_back(remainders[i].binary_basis_limbs[1].element * shift_1);
3026
2.23k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[2].element);
3027
2.23k
            limb_2_accumulator.emplace_back(remainders[i].binary_basis_limbs[3].element * shift_1);
3028
2.23k
            prime_limb_accumulator.emplace_back(remainders[i].prime_basis_limb);
3029
2.23k
        }
3030
2.23k
        for (const auto& add : to_add) {
3031
2.23k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[0].element);
3032
2.23k
            limb_0_accumulator.emplace_back(-add.binary_basis_limbs[1].element * shift_1);
3033
2.23k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[2].element);
3034
2.23k
            limb_2_accumulator.emplace_back(-add.binary_basis_limbs[3].element * shift_1);
3035
2.23k
            prime_limb_accumulator.emplace_back(-add.prime_basis_limb);
3036
2.23k
        }
3037
3038
2.23k
        field_t<Builder> accumulated_lo = field_t<Builder>::accumulate(limb_0_accumulator);
3039
2.23k
        field_t<Builder> accumulated_hi = field_t<Builder>::accumulate(limb_2_accumulator);
3040
2.23k
        if (accumulated_lo.is_constant()) {
3041
2.23k
            accumulated_lo =
3042
2.23k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_lo.get_value()));
3043
2.23k
        }
3044
2.23k
        if (accumulated_hi.is_constant()) {
3045
2.23k
            accumulated_hi =
3046
2.23k
                field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(accumulated_hi.get_value()));
3047
2.23k
        }
3048
2.23k
        field_t<Builder> remainder1 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3049
2.23k
                                                    : remainders[0].binary_basis_limbs[1].element;
3050
2.23k
        if (remainder1.is_constant()) {
3051
2.23k
            remainder1 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder1.get_value()));
3052
2.23k
        }
3053
2.23k
        field_t<Builder> remainder3 = no_remainders ? field_t<Builder>::from_witness_index(ctx, ctx->zero_idx)
3054
2.23k
                                                    : remainders[0].binary_basis_limbs[3].element;
3055
2.23k
        if (remainder3.is_constant()) {
3056
2.23k
            remainder3 = field_t<Builder>::from_witness_index(ctx, ctx->put_constant_variable(remainder3.get_value()));
3057
2.23k
        }
3058
2.23k
        field_t<Builder> remainder_limbs[4]{
3059
2.23k
            accumulated_lo,
3060
2.23k
            remainder1,
3061
2.23k
            accumulated_hi,
3062
2.23k
            remainder3,
3063
2.23k
        };
3064
2.23k
        field_t<Builder> remainder_prime_limb = field_t<Builder>::accumulate(prime_limb_accumulator);
3065
3066
        // We wish to show that left*right - quotient*remainder = 0 mod 2^t, we do this by collecting the limb
3067
        // products into two separate variables - carry_lo and carry_hi, which are still small enough not to wrap
3068
        // mod r Their first t/2 bits will equal, respectively, the first and second t/2 bits of the expresssion
3069
        // Thus it will suffice to check that each of them begins with t/2 zeroes. We do this by in fact assigning
3070
        // to these variables those expressions divided by 2^{t/2}. Since we have bounds on their ranage that are
3071
        // smaller than r, We can range check the divisions by the original range bounds divided by 2^{t/2}
3072
3073
2.23k
        field_t r0 = left[0].binary_basis_limbs[0].element.madd(
3074
2.23k
            right[0].binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3075
2.23k
        field_t r1 = b0.add_two(b1, -remainder_limbs[1]);
3076
2.23k
        const field_t r2 = c0.add_two(c1, c2);
3077
2.23k
        const field_t r3 = d0 + d1.add_two(d2, d3);
3078
3079
2.23k
        field_t carry_lo_0 = r0 * shift_right_2;
3080
2.23k
        field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3081
2.23k
        field_t carry_lo_2 = -(remainder_limbs[0] * shift_right_2);
3082
2.23k
        field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3083
3084
2.23k
        field_t t1 = carry_lo.add_two(-remainder_limbs[2], -(remainder_limbs[3] * shift_1));
3085
2.23k
        carry_lo += borrow_lo;
3086
2.23k
        field_t carry_hi_0 = r2 * shift_right_2;
3087
2.23k
        field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3088
2.23k
        field_t carry_hi_2 = t1 * shift_right_2;
3089
2.23k
        field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3090
3091
2.23k
        bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3092
3093
2.23k
        field_t<Builder> linear_terms(ctx, bb::fr(0));
3094
3095
2.23k
        linear_terms += -remainder_prime_limb;
3096
3097
        // This is where we show our identity is zero mod r (to use CRT we show it's zero mod r and mod 2^t)
3098
2.23k
        field_t<Builder>::evaluate_polynomial_identity(
3099
2.23k
            left[0].prime_basis_limb, right[0].prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3100
3101
2.23k
        const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3102
2.23k
        const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3103
3104
2.23k
        const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3105
3106
2.23k
        if constexpr (HasPlookup<Builder>) {
3107
2.23k
            carry_lo = carry_lo.normalize();
3108
2.23k
            carry_hi = carry_hi.normalize();
3109
2.23k
            ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(),
3110
2.23k
                                              static_cast<size_t>(carry_lo_msb));
3111
2.23k
            ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(),
3112
2.23k
                                              static_cast<size_t>(carry_hi_msb));
3113
3114
2.23k
        } else {
3115
2.23k
            if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3116
2.23k
                field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3117
2.23k
                carry_combined = carry_combined.normalize();
3118
2.23k
                const auto accumulators = ctx->decompose_into_base4_accumulators(
3119
2.23k
                    carry_combined.get_normalized_witness_index(),
3120
2.23k
                    static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3121
2.23k
                    "bigfield: carry_combined too large in unsafe_evaluate_multiple_multiply_add.");
3122
2.23k
                field_t<Builder> accumulator_midpoint = field_t<Builder>::from_witness_index(
3123
2.23k
                    ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3124
2.23k
                carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3125
2.23k
            } else {
3126
2.23k
                carry_lo = carry_lo.normalize();
3127
2.23k
                carry_hi = carry_hi.normalize();
3128
2.23k
                ctx->decompose_into_base4_accumulators(
3129
2.23k
                    carry_lo.get_normalized_witness_index(),
3130
2.23k
                    static_cast<size_t>(carry_lo_msb),
3131
2.23k
                    "bigfield: carry_lo too large in unsafe_evaluate_multiple_multiply_add.");
3132
2.23k
                ctx->decompose_into_base4_accumulators(
3133
2.23k
                    carry_hi.get_normalized_witness_index(),
3134
2.23k
                    static_cast<size_t>(carry_hi_msb),
3135
2.23k
                    "bigfield: carry_hi too large in unsafe_evaluate_multiple_multiply_add.");
3136
2.23k
            }
3137
2.23k
        }
3138
2.23k
    }
3139
2.23k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS9_SaIS9_EESE_SE_RKS9_SE_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS6_SaIS6_EESB_SB_RKS6_SB_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS8_SaIS8_EESD_SD_RKS8_SD_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E37unsafe_evaluate_multiple_multiply_addERKSt6vectorIS7_SaIS7_EESC_SC_RKS7_SC_
3140
3141
template <typename Builder, typename T>
3142
void bigfield<Builder, T>::unsafe_evaluate_square_add(const bigfield& left,
3143
                                                      const std::vector<bigfield>& to_add,
3144
                                                      const bigfield& quotient,
3145
                                                      const bigfield& remainder)
3146
381k
{
3147
381k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3148
3149
381k
    if (HasPlookup<Builder>) {
3150
381k
        unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder });
3151
381k
        return;
3152
381k
    }
3153
3154
    // Sanity checks
3155
0
    left.sanity_check();
3156
0
    remainder.sanity_check();
3157
0
    quotient.sanity_check();
3158
0
    for (auto& el : to_add) {
3159
0
        el.sanity_check();
3160
0
    }
3161
3162
0
    Builder* ctx = left.context == nullptr ? quotient.context : left.context;
3163
3164
0
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[0].maximum_value);
3165
0
    max_b0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3166
0
    max_b0 += max_b0;
3167
0
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[1].maximum_value);
3168
0
    max_c0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3169
0
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[0].maximum_value);
3170
0
    max_c1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3171
0
    max_c1 += max_c1;
3172
0
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * left.binary_basis_limbs[0].maximum_value);
3173
0
    max_d0 += (neg_modulus_limbs_u256[3] << NUM_LIMB_BITS);
3174
0
    max_d0 += max_d0;
3175
0
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[1].maximum_value);
3176
0
    max_d1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3177
0
    max_d1 += max_d1;
3178
3179
0
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * left.binary_basis_limbs[0].maximum_value;
3180
0
    max_r0 += (neg_modulus_limbs_u256[0] << NUM_LIMB_BITS);
3181
3182
0
    const uint512_t max_r1 = max_b0;
3183
0
    const uint512_t max_r2 = max_c0 + max_c1;
3184
0
    const uint512_t max_r3 = max_d0 + max_d1;
3185
3186
0
    uint512_t max_a0(0);
3187
0
    uint512_t max_a1(1);
3188
0
    for (size_t i = 0; i < to_add.size(); ++i) {
3189
0
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
3190
0
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
3191
0
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
3192
0
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
3193
0
    }
3194
0
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
3195
0
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1;
3196
3197
0
    uint64_t max_lo_bits = max_lo.get_msb() + 1;
3198
0
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
3199
0
    if ((max_lo_bits & 1ULL) == 1ULL) {
3200
0
        ++max_lo_bits;
3201
0
    }
3202
0
    if ((max_hi_bits & 1ULL) == 1ULL) {
3203
0
        ++max_hi_bits;
3204
0
    }
3205
3206
0
    field_t half(ctx, bb::fr(2).invert());
3207
0
    field_t two(ctx, bb::fr(2));
3208
0
    field_t b_quotient_0 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
3209
0
    field_t b_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
3210
3211
0
    field_t c_quotient_0 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
3212
0
    field_t c_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
3213
3214
0
    field_t d_quotient_0 = (quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
3215
0
    field_t d_quotient_1 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
3216
0
    field_t d_quotient_2 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
3217
0
    field_t d_quotient_3 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
3218
3219
0
    const field_t b0 =
3220
0
        two * left.binary_basis_limbs[1].element.madd(left.binary_basis_limbs[0].element, b_quotient_0 * half);
3221
3222
0
    const field_t c0 = left.binary_basis_limbs[1].element.madd(
3223
0
        left.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
3224
0
    const field_t c1 =
3225
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[0].element, c_quotient_0 * half);
3226
3227
0
    const field_t d0 =
3228
0
        two * left.binary_basis_limbs[3].element.madd(left.binary_basis_limbs[0].element, d_quotient_0 * half);
3229
3230
0
    const field_t d1 =
3231
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[1].element, d_quotient_1 * half);
3232
3233
0
    const field_t r0 = left.binary_basis_limbs[0].element.madd(
3234
0
        left.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3235
3236
0
    const field_t r1 = b0.add_two(b_quotient_1, -remainder.binary_basis_limbs[1].element);
3237
0
    const field_t r2 = c0.add_two(c_quotient_1, c1);
3238
0
    const field_t r3 = d0.add_two(d_quotient_2, d1) + d_quotient_3;
3239
3240
0
    field_t carry_lo_0 = r0 * shift_right_2;
3241
0
    field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3242
0
    field_t carry_lo_2 = -(remainder.binary_basis_limbs[0].element * shift_right_2);
3243
0
    field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3244
3245
0
    for (const auto& add_element : to_add) {
3246
0
        carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
3247
0
                                    add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
3248
0
    }
3249
3250
0
    field_t t1 = carry_lo.add_two(-remainder.binary_basis_limbs[2].element,
3251
0
                                  -(remainder.binary_basis_limbs[3].element * shift_1));
3252
0
    field_t carry_hi_0 = r2 * shift_right_2;
3253
0
    field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3254
0
    field_t carry_hi_2 = t1 * shift_right_2;
3255
0
    field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3256
3257
0
    for (const auto& add_element : to_add) {
3258
0
        carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
3259
0
                                    add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
3260
0
    }
3261
3262
0
    bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3263
0
    field_t<Builder> linear_terms = -remainder.prime_basis_limb;
3264
0
    if (to_add.size() >= 2) {
3265
0
        for (size_t i = 0; i < to_add.size() / 2; i += 1) {
3266
0
            linear_terms = linear_terms.add_two(to_add[2 * i].prime_basis_limb, to_add[2 * i + 1].prime_basis_limb);
3267
0
        }
3268
0
    }
3269
0
    if ((to_add.size() & 1UL) == 1UL) {
3270
0
        linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
3271
0
    }
3272
0
    field_t<Builder>::evaluate_polynomial_identity(
3273
0
        left.prime_basis_limb, left.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3274
3275
0
    const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3276
0
    const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3277
3278
0
    const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3279
0
    if constexpr (HasPlookup<Builder>) {
3280
0
        carry_lo = carry_lo.normalize();
3281
0
        carry_hi = carry_hi.normalize();
3282
0
        ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), static_cast<size_t>(carry_lo_msb));
3283
0
        ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), static_cast<size_t>(carry_hi_msb));
3284
3285
0
    } else {
3286
0
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3287
0
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3288
0
            carry_combined = carry_combined.normalize();
3289
0
            const auto accumulators = ctx->decompose_into_base4_accumulators(
3290
0
                carry_combined.get_normalized_witness_index(),
3291
0
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3292
0
                "bigfield: carry_combined too large in unsafe_evaluate_square_add.");
3293
0
            field_t<Builder> accumulator_midpoint =
3294
0
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3295
0
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3296
0
        } else {
3297
0
            carry_lo = carry_lo.normalize();
3298
0
            carry_hi = carry_hi.normalize();
3299
0
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
3300
0
                                                   static_cast<size_t>(carry_lo_msb),
3301
0
                                                   "bigfield: carry_lo too large in unsafe_evaluate_square_add.");
3302
0
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
3303
0
                                                   static_cast<size_t>(carry_hi_msb),
3304
0
                                                   "bigfield: carry_hi too large in unsafe_evaluate_square_add");
3305
0
        }
3306
0
    }
3307
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE26unsafe_evaluate_square_addERKS6_RKSt6vectorIS6_SaIS6_EES8_S8_
Line
Count
Source
3146
357k
{
3147
357k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3148
3149
357k
    if (HasPlookup<Builder>) {
3150
357k
        unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder });
3151
357k
        return;
3152
357k
    }
3153
3154
    // Sanity checks
3155
0
    left.sanity_check();
3156
0
    remainder.sanity_check();
3157
0
    quotient.sanity_check();
3158
0
    for (auto& el : to_add) {
3159
0
        el.sanity_check();
3160
0
    }
3161
3162
0
    Builder* ctx = left.context == nullptr ? quotient.context : left.context;
3163
3164
0
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[0].maximum_value);
3165
0
    max_b0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3166
0
    max_b0 += max_b0;
3167
0
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[1].maximum_value);
3168
0
    max_c0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3169
0
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[0].maximum_value);
3170
0
    max_c1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3171
0
    max_c1 += max_c1;
3172
0
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * left.binary_basis_limbs[0].maximum_value);
3173
0
    max_d0 += (neg_modulus_limbs_u256[3] << NUM_LIMB_BITS);
3174
0
    max_d0 += max_d0;
3175
0
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[1].maximum_value);
3176
0
    max_d1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3177
0
    max_d1 += max_d1;
3178
3179
0
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * left.binary_basis_limbs[0].maximum_value;
3180
0
    max_r0 += (neg_modulus_limbs_u256[0] << NUM_LIMB_BITS);
3181
3182
0
    const uint512_t max_r1 = max_b0;
3183
0
    const uint512_t max_r2 = max_c0 + max_c1;
3184
0
    const uint512_t max_r3 = max_d0 + max_d1;
3185
3186
0
    uint512_t max_a0(0);
3187
0
    uint512_t max_a1(1);
3188
0
    for (size_t i = 0; i < to_add.size(); ++i) {
3189
0
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
3190
0
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
3191
0
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
3192
0
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
3193
0
    }
3194
0
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
3195
0
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1;
3196
3197
0
    uint64_t max_lo_bits = max_lo.get_msb() + 1;
3198
0
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
3199
0
    if ((max_lo_bits & 1ULL) == 1ULL) {
3200
0
        ++max_lo_bits;
3201
0
    }
3202
0
    if ((max_hi_bits & 1ULL) == 1ULL) {
3203
0
        ++max_hi_bits;
3204
0
    }
3205
3206
0
    field_t half(ctx, bb::fr(2).invert());
3207
0
    field_t two(ctx, bb::fr(2));
3208
0
    field_t b_quotient_0 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
3209
0
    field_t b_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
3210
3211
0
    field_t c_quotient_0 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
3212
0
    field_t c_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
3213
3214
0
    field_t d_quotient_0 = (quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
3215
0
    field_t d_quotient_1 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
3216
0
    field_t d_quotient_2 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
3217
0
    field_t d_quotient_3 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
3218
3219
0
    const field_t b0 =
3220
0
        two * left.binary_basis_limbs[1].element.madd(left.binary_basis_limbs[0].element, b_quotient_0 * half);
3221
3222
0
    const field_t c0 = left.binary_basis_limbs[1].element.madd(
3223
0
        left.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
3224
0
    const field_t c1 =
3225
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[0].element, c_quotient_0 * half);
3226
3227
0
    const field_t d0 =
3228
0
        two * left.binary_basis_limbs[3].element.madd(left.binary_basis_limbs[0].element, d_quotient_0 * half);
3229
3230
0
    const field_t d1 =
3231
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[1].element, d_quotient_1 * half);
3232
3233
0
    const field_t r0 = left.binary_basis_limbs[0].element.madd(
3234
0
        left.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3235
3236
0
    const field_t r1 = b0.add_two(b_quotient_1, -remainder.binary_basis_limbs[1].element);
3237
0
    const field_t r2 = c0.add_two(c_quotient_1, c1);
3238
0
    const field_t r3 = d0.add_two(d_quotient_2, d1) + d_quotient_3;
3239
3240
0
    field_t carry_lo_0 = r0 * shift_right_2;
3241
0
    field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3242
0
    field_t carry_lo_2 = -(remainder.binary_basis_limbs[0].element * shift_right_2);
3243
0
    field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3244
3245
0
    for (const auto& add_element : to_add) {
3246
0
        carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
3247
0
                                    add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
3248
0
    }
3249
3250
0
    field_t t1 = carry_lo.add_two(-remainder.binary_basis_limbs[2].element,
3251
0
                                  -(remainder.binary_basis_limbs[3].element * shift_1));
3252
0
    field_t carry_hi_0 = r2 * shift_right_2;
3253
0
    field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3254
0
    field_t carry_hi_2 = t1 * shift_right_2;
3255
0
    field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3256
3257
0
    for (const auto& add_element : to_add) {
3258
0
        carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
3259
0
                                    add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
3260
0
    }
3261
3262
0
    bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3263
0
    field_t<Builder> linear_terms = -remainder.prime_basis_limb;
3264
0
    if (to_add.size() >= 2) {
3265
0
        for (size_t i = 0; i < to_add.size() / 2; i += 1) {
3266
0
            linear_terms = linear_terms.add_two(to_add[2 * i].prime_basis_limb, to_add[2 * i + 1].prime_basis_limb);
3267
0
        }
3268
0
    }
3269
0
    if ((to_add.size() & 1UL) == 1UL) {
3270
0
        linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
3271
0
    }
3272
0
    field_t<Builder>::evaluate_polynomial_identity(
3273
0
        left.prime_basis_limb, left.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3274
3275
0
    const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3276
0
    const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3277
3278
0
    const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3279
0
    if constexpr (HasPlookup<Builder>) {
3280
0
        carry_lo = carry_lo.normalize();
3281
0
        carry_hi = carry_hi.normalize();
3282
0
        ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), static_cast<size_t>(carry_lo_msb));
3283
0
        ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), static_cast<size_t>(carry_hi_msb));
3284
3285
0
    } else {
3286
0
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3287
0
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3288
0
            carry_combined = carry_combined.normalize();
3289
0
            const auto accumulators = ctx->decompose_into_base4_accumulators(
3290
0
                carry_combined.get_normalized_witness_index(),
3291
0
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3292
0
                "bigfield: carry_combined too large in unsafe_evaluate_square_add.");
3293
0
            field_t<Builder> accumulator_midpoint =
3294
0
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3295
0
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3296
0
        } else {
3297
0
            carry_lo = carry_lo.normalize();
3298
0
            carry_hi = carry_hi.normalize();
3299
0
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
3300
0
                                                   static_cast<size_t>(carry_lo_msb),
3301
0
                                                   "bigfield: carry_lo too large in unsafe_evaluate_square_add.");
3302
0
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
3303
0
                                                   static_cast<size_t>(carry_hi_msb),
3304
0
                                                   "bigfield: carry_hi too large in unsafe_evaluate_square_add");
3305
0
        }
3306
0
    }
3307
0
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE26unsafe_evaluate_square_addERKS6_RKSt6vectorIS6_SaIS6_EES8_S8_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE26unsafe_evaluate_square_addERKS8_RKSt6vectorIS8_SaIS8_EESA_SA_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_
Line
Count
Source
3146
1.01k
{
3147
1.01k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3148
3149
1.01k
    if (HasPlookup<Builder>) {
3150
1.01k
        unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder });
3151
1.01k
        return;
3152
1.01k
    }
3153
3154
    // Sanity checks
3155
0
    left.sanity_check();
3156
0
    remainder.sanity_check();
3157
0
    quotient.sanity_check();
3158
0
    for (auto& el : to_add) {
3159
0
        el.sanity_check();
3160
0
    }
3161
3162
0
    Builder* ctx = left.context == nullptr ? quotient.context : left.context;
3163
3164
0
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[0].maximum_value);
3165
0
    max_b0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3166
0
    max_b0 += max_b0;
3167
0
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[1].maximum_value);
3168
0
    max_c0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3169
0
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[0].maximum_value);
3170
0
    max_c1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3171
0
    max_c1 += max_c1;
3172
0
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * left.binary_basis_limbs[0].maximum_value);
3173
0
    max_d0 += (neg_modulus_limbs_u256[3] << NUM_LIMB_BITS);
3174
0
    max_d0 += max_d0;
3175
0
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[1].maximum_value);
3176
0
    max_d1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3177
0
    max_d1 += max_d1;
3178
3179
0
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * left.binary_basis_limbs[0].maximum_value;
3180
0
    max_r0 += (neg_modulus_limbs_u256[0] << NUM_LIMB_BITS);
3181
3182
0
    const uint512_t max_r1 = max_b0;
3183
0
    const uint512_t max_r2 = max_c0 + max_c1;
3184
0
    const uint512_t max_r3 = max_d0 + max_d1;
3185
3186
0
    uint512_t max_a0(0);
3187
0
    uint512_t max_a1(1);
3188
0
    for (size_t i = 0; i < to_add.size(); ++i) {
3189
0
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
3190
0
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
3191
0
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
3192
0
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
3193
0
    }
3194
0
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
3195
0
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1;
3196
3197
0
    uint64_t max_lo_bits = max_lo.get_msb() + 1;
3198
0
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
3199
0
    if ((max_lo_bits & 1ULL) == 1ULL) {
3200
0
        ++max_lo_bits;
3201
0
    }
3202
0
    if ((max_hi_bits & 1ULL) == 1ULL) {
3203
0
        ++max_hi_bits;
3204
0
    }
3205
3206
0
    field_t half(ctx, bb::fr(2).invert());
3207
0
    field_t two(ctx, bb::fr(2));
3208
0
    field_t b_quotient_0 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
3209
0
    field_t b_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
3210
3211
0
    field_t c_quotient_0 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
3212
0
    field_t c_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
3213
3214
0
    field_t d_quotient_0 = (quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
3215
0
    field_t d_quotient_1 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
3216
0
    field_t d_quotient_2 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
3217
0
    field_t d_quotient_3 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
3218
3219
0
    const field_t b0 =
3220
0
        two * left.binary_basis_limbs[1].element.madd(left.binary_basis_limbs[0].element, b_quotient_0 * half);
3221
3222
0
    const field_t c0 = left.binary_basis_limbs[1].element.madd(
3223
0
        left.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
3224
0
    const field_t c1 =
3225
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[0].element, c_quotient_0 * half);
3226
3227
0
    const field_t d0 =
3228
0
        two * left.binary_basis_limbs[3].element.madd(left.binary_basis_limbs[0].element, d_quotient_0 * half);
3229
3230
0
    const field_t d1 =
3231
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[1].element, d_quotient_1 * half);
3232
3233
0
    const field_t r0 = left.binary_basis_limbs[0].element.madd(
3234
0
        left.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3235
3236
0
    const field_t r1 = b0.add_two(b_quotient_1, -remainder.binary_basis_limbs[1].element);
3237
0
    const field_t r2 = c0.add_two(c_quotient_1, c1);
3238
0
    const field_t r3 = d0.add_two(d_quotient_2, d1) + d_quotient_3;
3239
3240
0
    field_t carry_lo_0 = r0 * shift_right_2;
3241
0
    field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3242
0
    field_t carry_lo_2 = -(remainder.binary_basis_limbs[0].element * shift_right_2);
3243
0
    field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3244
3245
0
    for (const auto& add_element : to_add) {
3246
0
        carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
3247
0
                                    add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
3248
0
    }
3249
3250
0
    field_t t1 = carry_lo.add_two(-remainder.binary_basis_limbs[2].element,
3251
0
                                  -(remainder.binary_basis_limbs[3].element * shift_1));
3252
0
    field_t carry_hi_0 = r2 * shift_right_2;
3253
0
    field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3254
0
    field_t carry_hi_2 = t1 * shift_right_2;
3255
0
    field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3256
3257
0
    for (const auto& add_element : to_add) {
3258
0
        carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
3259
0
                                    add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
3260
0
    }
3261
3262
0
    bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3263
0
    field_t<Builder> linear_terms = -remainder.prime_basis_limb;
3264
0
    if (to_add.size() >= 2) {
3265
0
        for (size_t i = 0; i < to_add.size() / 2; i += 1) {
3266
0
            linear_terms = linear_terms.add_two(to_add[2 * i].prime_basis_limb, to_add[2 * i + 1].prime_basis_limb);
3267
0
        }
3268
0
    }
3269
0
    if ((to_add.size() & 1UL) == 1UL) {
3270
0
        linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
3271
0
    }
3272
0
    field_t<Builder>::evaluate_polynomial_identity(
3273
0
        left.prime_basis_limb, left.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3274
3275
0
    const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3276
0
    const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3277
3278
0
    const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3279
0
    if constexpr (HasPlookup<Builder>) {
3280
0
        carry_lo = carry_lo.normalize();
3281
0
        carry_hi = carry_hi.normalize();
3282
0
        ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), static_cast<size_t>(carry_lo_msb));
3283
0
        ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), static_cast<size_t>(carry_hi_msb));
3284
3285
0
    } else {
3286
0
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3287
0
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3288
0
            carry_combined = carry_combined.normalize();
3289
0
            const auto accumulators = ctx->decompose_into_base4_accumulators(
3290
0
                carry_combined.get_normalized_witness_index(),
3291
0
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3292
0
                "bigfield: carry_combined too large in unsafe_evaluate_square_add.");
3293
0
            field_t<Builder> accumulator_midpoint =
3294
0
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3295
0
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3296
0
        } else {
3297
0
            carry_lo = carry_lo.normalize();
3298
0
            carry_hi = carry_hi.normalize();
3299
0
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
3300
0
                                                   static_cast<size_t>(carry_lo_msb),
3301
0
                                                   "bigfield: carry_lo too large in unsafe_evaluate_square_add.");
3302
0
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
3303
0
                                                   static_cast<size_t>(carry_hi_msb),
3304
0
                                                   "bigfield: carry_hi too large in unsafe_evaluate_square_add");
3305
0
        }
3306
0
    }
3307
0
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE26unsafe_evaluate_square_addERKS9_RKSt6vectorIS9_SaIS9_EESB_SB_
Line
Count
Source
3146
20.8k
{
3147
20.8k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3148
3149
20.8k
    if (HasPlookup<Builder>) {
3150
20.8k
        unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder });
3151
20.8k
        return;
3152
20.8k
    }
3153
3154
    // Sanity checks
3155
0
    left.sanity_check();
3156
0
    remainder.sanity_check();
3157
0
    quotient.sanity_check();
3158
0
    for (auto& el : to_add) {
3159
0
        el.sanity_check();
3160
0
    }
3161
3162
0
    Builder* ctx = left.context == nullptr ? quotient.context : left.context;
3163
3164
0
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[0].maximum_value);
3165
0
    max_b0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3166
0
    max_b0 += max_b0;
3167
0
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[1].maximum_value);
3168
0
    max_c0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3169
0
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[0].maximum_value);
3170
0
    max_c1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3171
0
    max_c1 += max_c1;
3172
0
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * left.binary_basis_limbs[0].maximum_value);
3173
0
    max_d0 += (neg_modulus_limbs_u256[3] << NUM_LIMB_BITS);
3174
0
    max_d0 += max_d0;
3175
0
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[1].maximum_value);
3176
0
    max_d1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3177
0
    max_d1 += max_d1;
3178
3179
0
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * left.binary_basis_limbs[0].maximum_value;
3180
0
    max_r0 += (neg_modulus_limbs_u256[0] << NUM_LIMB_BITS);
3181
3182
0
    const uint512_t max_r1 = max_b0;
3183
0
    const uint512_t max_r2 = max_c0 + max_c1;
3184
0
    const uint512_t max_r3 = max_d0 + max_d1;
3185
3186
0
    uint512_t max_a0(0);
3187
0
    uint512_t max_a1(1);
3188
0
    for (size_t i = 0; i < to_add.size(); ++i) {
3189
0
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
3190
0
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
3191
0
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
3192
0
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
3193
0
    }
3194
0
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
3195
0
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1;
3196
3197
0
    uint64_t max_lo_bits = max_lo.get_msb() + 1;
3198
0
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
3199
0
    if ((max_lo_bits & 1ULL) == 1ULL) {
3200
0
        ++max_lo_bits;
3201
0
    }
3202
0
    if ((max_hi_bits & 1ULL) == 1ULL) {
3203
0
        ++max_hi_bits;
3204
0
    }
3205
3206
0
    field_t half(ctx, bb::fr(2).invert());
3207
0
    field_t two(ctx, bb::fr(2));
3208
0
    field_t b_quotient_0 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
3209
0
    field_t b_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
3210
3211
0
    field_t c_quotient_0 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
3212
0
    field_t c_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
3213
3214
0
    field_t d_quotient_0 = (quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
3215
0
    field_t d_quotient_1 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
3216
0
    field_t d_quotient_2 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
3217
0
    field_t d_quotient_3 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
3218
3219
0
    const field_t b0 =
3220
0
        two * left.binary_basis_limbs[1].element.madd(left.binary_basis_limbs[0].element, b_quotient_0 * half);
3221
3222
0
    const field_t c0 = left.binary_basis_limbs[1].element.madd(
3223
0
        left.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
3224
0
    const field_t c1 =
3225
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[0].element, c_quotient_0 * half);
3226
3227
0
    const field_t d0 =
3228
0
        two * left.binary_basis_limbs[3].element.madd(left.binary_basis_limbs[0].element, d_quotient_0 * half);
3229
3230
0
    const field_t d1 =
3231
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[1].element, d_quotient_1 * half);
3232
3233
0
    const field_t r0 = left.binary_basis_limbs[0].element.madd(
3234
0
        left.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3235
3236
0
    const field_t r1 = b0.add_two(b_quotient_1, -remainder.binary_basis_limbs[1].element);
3237
0
    const field_t r2 = c0.add_two(c_quotient_1, c1);
3238
0
    const field_t r3 = d0.add_two(d_quotient_2, d1) + d_quotient_3;
3239
3240
0
    field_t carry_lo_0 = r0 * shift_right_2;
3241
0
    field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3242
0
    field_t carry_lo_2 = -(remainder.binary_basis_limbs[0].element * shift_right_2);
3243
0
    field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3244
3245
0
    for (const auto& add_element : to_add) {
3246
0
        carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
3247
0
                                    add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
3248
0
    }
3249
3250
0
    field_t t1 = carry_lo.add_two(-remainder.binary_basis_limbs[2].element,
3251
0
                                  -(remainder.binary_basis_limbs[3].element * shift_1));
3252
0
    field_t carry_hi_0 = r2 * shift_right_2;
3253
0
    field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3254
0
    field_t carry_hi_2 = t1 * shift_right_2;
3255
0
    field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3256
3257
0
    for (const auto& add_element : to_add) {
3258
0
        carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
3259
0
                                    add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
3260
0
    }
3261
3262
0
    bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3263
0
    field_t<Builder> linear_terms = -remainder.prime_basis_limb;
3264
0
    if (to_add.size() >= 2) {
3265
0
        for (size_t i = 0; i < to_add.size() / 2; i += 1) {
3266
0
            linear_terms = linear_terms.add_two(to_add[2 * i].prime_basis_limb, to_add[2 * i + 1].prime_basis_limb);
3267
0
        }
3268
0
    }
3269
0
    if ((to_add.size() & 1UL) == 1UL) {
3270
0
        linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
3271
0
    }
3272
0
    field_t<Builder>::evaluate_polynomial_identity(
3273
0
        left.prime_basis_limb, left.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3274
3275
0
    const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3276
0
    const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3277
3278
0
    const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3279
0
    if constexpr (HasPlookup<Builder>) {
3280
0
        carry_lo = carry_lo.normalize();
3281
0
        carry_hi = carry_hi.normalize();
3282
0
        ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), static_cast<size_t>(carry_lo_msb));
3283
0
        ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), static_cast<size_t>(carry_hi_msb));
3284
3285
0
    } else {
3286
0
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3287
0
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3288
0
            carry_combined = carry_combined.normalize();
3289
0
            const auto accumulators = ctx->decompose_into_base4_accumulators(
3290
0
                carry_combined.get_normalized_witness_index(),
3291
0
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3292
0
                "bigfield: carry_combined too large in unsafe_evaluate_square_add.");
3293
0
            field_t<Builder> accumulator_midpoint =
3294
0
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3295
0
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3296
0
        } else {
3297
0
            carry_lo = carry_lo.normalize();
3298
0
            carry_hi = carry_hi.normalize();
3299
0
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
3300
0
                                                   static_cast<size_t>(carry_lo_msb),
3301
0
                                                   "bigfield: carry_lo too large in unsafe_evaluate_square_add.");
3302
0
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
3303
0
                                                   static_cast<size_t>(carry_hi_msb),
3304
0
                                                   "bigfield: carry_hi too large in unsafe_evaluate_square_add");
3305
0
        }
3306
0
    }
3307
0
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE26unsafe_evaluate_square_addERKS9_RKSt6vectorIS9_SaIS9_EESB_SB_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_
Line
Count
Source
3146
1.31k
{
3147
1.31k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3148
3149
1.31k
    if (HasPlookup<Builder>) {
3150
1.31k
        unsafe_evaluate_multiply_add(left, left, to_add, quotient, { remainder });
3151
1.31k
        return;
3152
1.31k
    }
3153
3154
    // Sanity checks
3155
0
    left.sanity_check();
3156
0
    remainder.sanity_check();
3157
0
    quotient.sanity_check();
3158
0
    for (auto& el : to_add) {
3159
0
        el.sanity_check();
3160
0
    }
3161
3162
0
    Builder* ctx = left.context == nullptr ? quotient.context : left.context;
3163
3164
0
    uint512_t max_b0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[0].maximum_value);
3165
0
    max_b0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3166
0
    max_b0 += max_b0;
3167
0
    uint512_t max_c0 = (left.binary_basis_limbs[1].maximum_value * left.binary_basis_limbs[1].maximum_value);
3168
0
    max_c0 += (neg_modulus_limbs_u256[1] << NUM_LIMB_BITS);
3169
0
    uint512_t max_c1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[0].maximum_value);
3170
0
    max_c1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3171
0
    max_c1 += max_c1;
3172
0
    uint512_t max_d0 = (left.binary_basis_limbs[3].maximum_value * left.binary_basis_limbs[0].maximum_value);
3173
0
    max_d0 += (neg_modulus_limbs_u256[3] << NUM_LIMB_BITS);
3174
0
    max_d0 += max_d0;
3175
0
    uint512_t max_d1 = (left.binary_basis_limbs[2].maximum_value * left.binary_basis_limbs[1].maximum_value);
3176
0
    max_d1 += (neg_modulus_limbs_u256[2] << NUM_LIMB_BITS);
3177
0
    max_d1 += max_d1;
3178
3179
0
    uint512_t max_r0 = left.binary_basis_limbs[0].maximum_value * left.binary_basis_limbs[0].maximum_value;
3180
0
    max_r0 += (neg_modulus_limbs_u256[0] << NUM_LIMB_BITS);
3181
3182
0
    const uint512_t max_r1 = max_b0;
3183
0
    const uint512_t max_r2 = max_c0 + max_c1;
3184
0
    const uint512_t max_r3 = max_d0 + max_d1;
3185
3186
0
    uint512_t max_a0(0);
3187
0
    uint512_t max_a1(1);
3188
0
    for (size_t i = 0; i < to_add.size(); ++i) {
3189
0
        max_a0 += to_add[i].binary_basis_limbs[0].maximum_value +
3190
0
                  (to_add[i].binary_basis_limbs[1].maximum_value << NUM_LIMB_BITS);
3191
0
        max_a1 += to_add[i].binary_basis_limbs[2].maximum_value +
3192
0
                  (to_add[i].binary_basis_limbs[3].maximum_value << NUM_LIMB_BITS);
3193
0
    }
3194
0
    const uint512_t max_lo = max_r0 + (max_r1 << NUM_LIMB_BITS) + max_a0;
3195
0
    const uint512_t max_hi = max_r2 + (max_r3 << NUM_LIMB_BITS) + max_a1;
3196
3197
0
    uint64_t max_lo_bits = max_lo.get_msb() + 1;
3198
0
    uint64_t max_hi_bits = max_hi.get_msb() + 1;
3199
0
    if ((max_lo_bits & 1ULL) == 1ULL) {
3200
0
        ++max_lo_bits;
3201
0
    }
3202
0
    if ((max_hi_bits & 1ULL) == 1ULL) {
3203
0
        ++max_hi_bits;
3204
0
    }
3205
3206
0
    field_t half(ctx, bb::fr(2).invert());
3207
0
    field_t two(ctx, bb::fr(2));
3208
0
    field_t b_quotient_0 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[0]);
3209
0
    field_t b_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[1]);
3210
3211
0
    field_t c_quotient_0 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[0]);
3212
0
    field_t c_quotient_1 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[2]);
3213
3214
0
    field_t d_quotient_0 = (quotient.binary_basis_limbs[3].element * neg_modulus_limbs[0]);
3215
0
    field_t d_quotient_1 = (quotient.binary_basis_limbs[1].element * neg_modulus_limbs[2]);
3216
0
    field_t d_quotient_2 = (quotient.binary_basis_limbs[0].element * neg_modulus_limbs[3]);
3217
0
    field_t d_quotient_3 = (quotient.binary_basis_limbs[2].element * neg_modulus_limbs[1]);
3218
3219
0
    const field_t b0 =
3220
0
        two * left.binary_basis_limbs[1].element.madd(left.binary_basis_limbs[0].element, b_quotient_0 * half);
3221
3222
0
    const field_t c0 = left.binary_basis_limbs[1].element.madd(
3223
0
        left.binary_basis_limbs[1].element, quotient.binary_basis_limbs[1].element * neg_modulus_limbs[1]);
3224
0
    const field_t c1 =
3225
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[0].element, c_quotient_0 * half);
3226
3227
0
    const field_t d0 =
3228
0
        two * left.binary_basis_limbs[3].element.madd(left.binary_basis_limbs[0].element, d_quotient_0 * half);
3229
3230
0
    const field_t d1 =
3231
0
        two * left.binary_basis_limbs[2].element.madd(left.binary_basis_limbs[1].element, d_quotient_1 * half);
3232
3233
0
    const field_t r0 = left.binary_basis_limbs[0].element.madd(
3234
0
        left.binary_basis_limbs[0].element, quotient.binary_basis_limbs[0].element * neg_modulus_limbs[0]);
3235
3236
0
    const field_t r1 = b0.add_two(b_quotient_1, -remainder.binary_basis_limbs[1].element);
3237
0
    const field_t r2 = c0.add_two(c_quotient_1, c1);
3238
0
    const field_t r3 = d0.add_two(d_quotient_2, d1) + d_quotient_3;
3239
3240
0
    field_t carry_lo_0 = r0 * shift_right_2;
3241
0
    field_t carry_lo_1 = r1 * (shift_1 * shift_right_2);
3242
0
    field_t carry_lo_2 = -(remainder.binary_basis_limbs[0].element * shift_right_2);
3243
0
    field_t carry_lo = carry_lo_0.add_two(carry_lo_1, carry_lo_2);
3244
3245
0
    for (const auto& add_element : to_add) {
3246
0
        carry_lo = carry_lo.add_two(add_element.binary_basis_limbs[0].element * shift_right_2,
3247
0
                                    add_element.binary_basis_limbs[1].element * (shift_1 * shift_right_2));
3248
0
    }
3249
3250
0
    field_t t1 = carry_lo.add_two(-remainder.binary_basis_limbs[2].element,
3251
0
                                  -(remainder.binary_basis_limbs[3].element * shift_1));
3252
0
    field_t carry_hi_0 = r2 * shift_right_2;
3253
0
    field_t carry_hi_1 = r3 * (shift_1 * shift_right_2);
3254
0
    field_t carry_hi_2 = t1 * shift_right_2;
3255
0
    field_t carry_hi = carry_hi_0.add_two(carry_hi_1, carry_hi_2);
3256
3257
0
    for (const auto& add_element : to_add) {
3258
0
        carry_hi = carry_hi.add_two(add_element.binary_basis_limbs[2].element * shift_right_2,
3259
0
                                    add_element.binary_basis_limbs[3].element * (shift_1 * shift_right_2));
3260
0
    }
3261
3262
0
    bb::fr neg_prime = -bb::fr(uint256_t(target_basis.modulus));
3263
0
    field_t<Builder> linear_terms = -remainder.prime_basis_limb;
3264
0
    if (to_add.size() >= 2) {
3265
0
        for (size_t i = 0; i < to_add.size() / 2; i += 1) {
3266
0
            linear_terms = linear_terms.add_two(to_add[2 * i].prime_basis_limb, to_add[2 * i + 1].prime_basis_limb);
3267
0
        }
3268
0
    }
3269
0
    if ((to_add.size() & 1UL) == 1UL) {
3270
0
        linear_terms += to_add[to_add.size() - 1].prime_basis_limb;
3271
0
    }
3272
0
    field_t<Builder>::evaluate_polynomial_identity(
3273
0
        left.prime_basis_limb, left.prime_basis_limb, quotient.prime_basis_limb * neg_prime, linear_terms);
3274
3275
0
    const uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS);
3276
0
    const uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS);
3277
3278
0
    const bb::fr carry_lo_shift(uint256_t(uint256_t(1) << carry_lo_msb));
3279
0
    if constexpr (HasPlookup<Builder>) {
3280
0
        carry_lo = carry_lo.normalize();
3281
0
        carry_hi = carry_hi.normalize();
3282
0
        ctx->decompose_into_default_range(carry_lo.get_normalized_witness_index(), static_cast<size_t>(carry_lo_msb));
3283
0
        ctx->decompose_into_default_range(carry_hi.get_normalized_witness_index(), static_cast<size_t>(carry_hi_msb));
3284
3285
0
    } else {
3286
0
        if ((carry_hi_msb + carry_lo_msb) < field_t<Builder>::modulus.get_msb()) {
3287
0
            field_t carry_combined = carry_lo + (carry_hi * carry_lo_shift);
3288
0
            carry_combined = carry_combined.normalize();
3289
0
            const auto accumulators = ctx->decompose_into_base4_accumulators(
3290
0
                carry_combined.get_normalized_witness_index(),
3291
0
                static_cast<size_t>(carry_lo_msb + carry_hi_msb),
3292
0
                "bigfield: carry_combined too large in unsafe_evaluate_square_add.");
3293
0
            field_t<Builder> accumulator_midpoint =
3294
0
                field_t<Builder>::from_witness_index(ctx, accumulators[static_cast<size_t>((carry_hi_msb / 2) - 1)]);
3295
0
            carry_hi.assert_equal(accumulator_midpoint, "bigfield multiply range check failed");
3296
0
        } else {
3297
0
            carry_lo = carry_lo.normalize();
3298
0
            carry_hi = carry_hi.normalize();
3299
0
            ctx->decompose_into_base4_accumulators(carry_lo.get_normalized_witness_index(),
3300
0
                                                   static_cast<size_t>(carry_lo_msb),
3301
0
                                                   "bigfield: carry_lo too large in unsafe_evaluate_square_add.");
3302
0
            ctx->decompose_into_base4_accumulators(carry_hi.get_normalized_witness_index(),
3303
0
                                                   static_cast<size_t>(carry_hi_msb),
3304
0
                                                   "bigfield: carry_hi too large in unsafe_evaluate_square_add");
3305
0
        }
3306
0
    }
3307
0
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE26unsafe_evaluate_square_addERKS9_RKSt6vectorIS9_SaIS9_EESB_SB_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE26unsafe_evaluate_square_addERKS9_RKSt6vectorIS9_SaIS9_EESB_SB_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE26unsafe_evaluate_square_addERKS6_RKSt6vectorIS6_SaIS6_EES8_S8_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE26unsafe_evaluate_square_addERKS6_RKSt6vectorIS6_SaIS6_EES8_S8_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE26unsafe_evaluate_square_addERKS8_RKSt6vectorIS8_SaIS8_EESA_SA_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E26unsafe_evaluate_square_addERKS7_RKSt6vectorIS7_SaIS7_EES9_S9_
3308
3309
template <typename Builder, typename T>
3310
std::pair<uint512_t, uint512_t> bigfield<Builder, T>::compute_quotient_remainder_values(
3311
    const bigfield& a, const bigfield& b, const std::vector<bigfield>& to_add)
3312
222k
{
3313
222k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
0
    uint512_t add_values(0);
3316
0
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
0
    const uint1024_t left(a.get_value());
3322
0
    const uint1024_t right(b.get_value());
3323
0
    const uint1024_t add_right(add_values);
3324
0
    const uint1024_t modulus(target_basis.modulus);
3325
3326
0
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
0
    return { quotient_1024.lo, remainder_1024.lo };
3329
222k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE33compute_quotient_remainder_valuesERKS6_S8_RKSt6vectorIS6_SaIS6_EE
Line
Count
Source
3312
215k
{
3313
215k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
215k
    uint512_t add_values(0);
3316
215k
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
215k
    const uint1024_t left(a.get_value());
3322
215k
    const uint1024_t right(b.get_value());
3323
215k
    const uint1024_t add_right(add_values);
3324
215k
    const uint1024_t modulus(target_basis.modulus);
3325
3326
215k
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
215k
    return { quotient_1024.lo, remainder_1024.lo };
3329
215k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE33compute_quotient_remainder_valuesERKS6_S8_RKSt6vectorIS6_SaIS6_EE
Line
Count
Source
3312
38
{
3313
38
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
38
    uint512_t add_values(0);
3316
38
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
38
    const uint1024_t left(a.get_value());
3322
38
    const uint1024_t right(b.get_value());
3323
38
    const uint1024_t add_right(add_values);
3324
38
    const uint1024_t modulus(target_basis.modulus);
3325
3326
38
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
38
    return { quotient_1024.lo, remainder_1024.lo };
3329
38
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE33compute_quotient_remainder_valuesERKS8_SA_RKSt6vectorIS8_SaIS8_EE
Line
Count
Source
3312
20
{
3313
20
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
20
    uint512_t add_values(0);
3316
20
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
20
    const uint1024_t left(a.get_value());
3322
20
    const uint1024_t right(b.get_value());
3323
20
    const uint1024_t add_right(add_values);
3324
20
    const uint1024_t modulus(target_basis.modulus);
3325
3326
20
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
20
    return { quotient_1024.lo, remainder_1024.lo };
3329
20
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE
Line
Count
Source
3312
255
{
3313
255
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
255
    uint512_t add_values(0);
3316
255
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
255
    const uint1024_t left(a.get_value());
3322
255
    const uint1024_t right(b.get_value());
3323
255
    const uint1024_t add_right(add_values);
3324
255
    const uint1024_t modulus(target_basis.modulus);
3325
3326
255
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
255
    return { quotient_1024.lo, remainder_1024.lo };
3329
255
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE
Line
Count
Source
3312
1
{
3313
1
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
1
    uint512_t add_values(0);
3316
1
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
1
    const uint1024_t left(a.get_value());
3322
1
    const uint1024_t right(b.get_value());
3323
1
    const uint1024_t add_right(add_values);
3324
1
    const uint1024_t modulus(target_basis.modulus);
3325
3326
1
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
1
    return { quotient_1024.lo, remainder_1024.lo };
3329
1
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE33compute_quotient_remainder_valuesERKS9_SB_RKSt6vectorIS9_SaIS9_EE
Line
Count
Source
3312
6.19k
{
3313
6.19k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
6.19k
    uint512_t add_values(0);
3316
6.19k
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
6.19k
    const uint1024_t left(a.get_value());
3322
6.19k
    const uint1024_t right(b.get_value());
3323
6.19k
    const uint1024_t add_right(add_values);
3324
6.19k
    const uint1024_t modulus(target_basis.modulus);
3325
3326
6.19k
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
6.19k
    return { quotient_1024.lo, remainder_1024.lo };
3329
6.19k
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE33compute_quotient_remainder_valuesERKS9_SB_RKSt6vectorIS9_SaIS9_EE
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE
Line
Count
Source
3312
51
{
3313
51
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3314
3315
51
    uint512_t add_values(0);
3316
51
    for (const auto& add_element : to_add) {
3317
0
        add_element.reduction_check();
3318
0
        add_values += add_element.get_value();
3319
0
    }
3320
3321
51
    const uint1024_t left(a.get_value());
3322
51
    const uint1024_t right(b.get_value());
3323
51
    const uint1024_t add_right(add_values);
3324
51
    const uint1024_t modulus(target_basis.modulus);
3325
3326
51
    const auto [quotient_1024, remainder_1024] = (left * right + add_right).divmod(modulus);
3327
3328
51
    return { quotient_1024.lo, remainder_1024.lo };
3329
51
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE33compute_quotient_remainder_valuesERKS9_SB_RKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE33compute_quotient_remainder_valuesERKS9_SB_RKSt6vectorIS9_SaIS9_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE33compute_quotient_remainder_valuesERKS6_S8_RKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE33compute_quotient_remainder_valuesERKS6_S8_RKSt6vectorIS6_SaIS6_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE33compute_quotient_remainder_valuesERKS8_SA_RKSt6vectorIS8_SaIS8_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E33compute_quotient_remainder_valuesERKS7_S9_RKSt6vectorIS7_SaIS7_EE
3330
3331
template <typename Builder, typename T>
3332
uint512_t bigfield<Builder, T>::compute_maximum_quotient_value(const std::vector<uint512_t>& as,
3333
                                                               const std::vector<uint512_t>& bs,
3334
                                                               const std::vector<uint512_t>& to_add)
3335
1.20M
{
3336
1.20M
    ASSERT(as.size() == bs.size());
3337
1.20M
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
0
    uint512_t add_values(0);
3340
1.69M
    for (const auto& add_element : to_add) {
3341
1.69M
        add_values += add_element;
3342
1.69M
    }
3343
0
    uint1024_t product_sum(0);
3344
2.86M
    for (size_t i = 0; i < as.size(); i++) {
3345
1.66M
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
1.66M
    }
3347
0
    const uint1024_t add_right(add_values);
3348
0
    const uint1024_t modulus(target_basis.modulus);
3349
3350
0
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
0
    return quotient_1024.lo;
3353
0
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_SF_
Line
Count
Source
3335
1.10M
{
3336
1.10M
    ASSERT(as.size() == bs.size());
3337
1.10M
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
1.10M
    uint512_t add_values(0);
3340
1.56M
    for (const auto& add_element : to_add) {
3341
1.56M
        add_values += add_element;
3342
1.56M
    }
3343
1.10M
    uint1024_t product_sum(0);
3344
2.62M
    for (size_t i = 0; i < as.size(); i++) {
3345
1.51M
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
1.51M
    }
3347
1.10M
    const uint1024_t add_right(add_values);
3348
1.10M
    const uint1024_t modulus(target_basis.modulus);
3349
3350
1.10M
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
1.10M
    return quotient_1024.lo;
3353
1.10M
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_SF_
Line
Count
Source
3335
38
{
3336
38
    ASSERT(as.size() == bs.size());
3337
38
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
38
    uint512_t add_values(0);
3340
38
    for (const auto& add_element : to_add) {
3341
0
        add_values += add_element;
3342
0
    }
3343
38
    uint1024_t product_sum(0);
3344
76
    for (size_t i = 0; i < as.size(); i++) {
3345
38
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
38
    }
3347
38
    const uint1024_t add_right(add_values);
3348
38
    const uint1024_t modulus(target_basis.modulus);
3349
3350
38
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
38
    return quotient_1024.lo;
3353
38
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSA_9uint256_tEEESaISD_EESH_SH_
Line
Count
Source
3335
16
{
3336
16
    ASSERT(as.size() == bs.size());
3337
16
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
16
    uint512_t add_values(0);
3340
16
    for (const auto& add_element : to_add) {
3341
0
        add_values += add_element;
3342
0
    }
3343
16
    uint1024_t product_sum(0);
3344
32
    for (size_t i = 0; i < as.size(); i++) {
3345
16
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
16
    }
3347
16
    const uint1024_t add_right(add_values);
3348
16
    const uint1024_t modulus(target_basis.modulus);
3349
3350
16
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
16
    return quotient_1024.lo;
3353
16
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_
Line
Count
Source
3335
4.01k
{
3336
4.01k
    ASSERT(as.size() == bs.size());
3337
4.01k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
4.01k
    uint512_t add_values(0);
3340
5.10k
    for (const auto& add_element : to_add) {
3341
5.10k
        add_values += add_element;
3342
5.10k
    }
3343
4.01k
    uint1024_t product_sum(0);
3344
9.88k
    for (size_t i = 0; i < as.size(); i++) {
3345
5.87k
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
5.87k
    }
3347
4.01k
    const uint1024_t add_right(add_values);
3348
4.01k
    const uint1024_t modulus(target_basis.modulus);
3349
3350
4.01k
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
4.01k
    return quotient_1024.lo;
3353
4.01k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_
Line
Count
Source
3335
27
{
3336
27
    ASSERT(as.size() == bs.size());
3337
27
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
27
    uint512_t add_values(0);
3340
27
    for (const auto& add_element : to_add) {
3341
26
        add_values += add_element;
3342
26
    }
3343
27
    uint1024_t product_sum(0);
3344
54
    for (size_t i = 0; i < as.size(); i++) {
3345
27
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
27
    }
3347
27
    const uint1024_t add_right(add_values);
3348
27
    const uint1024_t modulus(target_basis.modulus);
3349
3350
27
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
27
    return quotient_1024.lo;
3353
27
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_SI_
Line
Count
Source
3335
86.4k
{
3336
86.4k
    ASSERT(as.size() == bs.size());
3337
86.4k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
86.4k
    uint512_t add_values(0);
3340
114k
    for (const auto& add_element : to_add) {
3341
114k
        add_values += add_element;
3342
114k
    }
3343
86.4k
    uint1024_t product_sum(0);
3344
214k
    for (size_t i = 0; i < as.size(); i++) {
3345
128k
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
128k
    }
3347
86.4k
    const uint1024_t add_right(add_values);
3348
86.4k
    const uint1024_t modulus(target_basis.modulus);
3349
3350
86.4k
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
86.4k
    return quotient_1024.lo;
3353
86.4k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_SI_
Line
Count
Source
3335
576
{
3336
576
    ASSERT(as.size() == bs.size());
3337
576
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
576
    uint512_t add_values(0);
3340
576
    for (const auto& add_element : to_add) {
3341
576
        add_values += add_element;
3342
576
    }
3343
576
    uint1024_t product_sum(0);
3344
1.15k
    for (size_t i = 0; i < as.size(); i++) {
3345
576
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
576
    }
3347
576
    const uint1024_t add_right(add_values);
3348
576
    const uint1024_t modulus(target_basis.modulus);
3349
3350
576
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
576
    return quotient_1024.lo;
3353
576
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_
Line
Count
Source
3335
5.56k
{
3336
5.56k
    ASSERT(as.size() == bs.size());
3337
5.56k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
5.56k
    uint512_t add_values(0);
3340
9.04k
    for (const auto& add_element : to_add) {
3341
9.04k
        add_values += add_element;
3342
9.04k
    }
3343
5.56k
    uint1024_t product_sum(0);
3344
15.9k
    for (size_t i = 0; i < as.size(); i++) {
3345
10.3k
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
10.3k
    }
3347
5.56k
    const uint1024_t add_right(add_values);
3348
5.56k
    const uint1024_t modulus(target_basis.modulus);
3349
3350
5.56k
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
5.56k
    return quotient_1024.lo;
3353
5.56k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_
Line
Count
Source
3335
10
{
3336
10
    ASSERT(as.size() == bs.size());
3337
10
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3338
3339
10
    uint512_t add_values(0);
3340
10
    for (const auto& add_element : to_add) {
3341
10
        add_values += add_element;
3342
10
    }
3343
10
    uint1024_t product_sum(0);
3344
20
    for (size_t i = 0; i < as.size(); i++) {
3345
10
        product_sum += uint1024_t(as[i]) * uint1024_t(bs[i]);
3346
10
    }
3347
10
    const uint1024_t add_right(add_values);
3348
10
    const uint1024_t modulus(target_basis.modulus);
3349
3350
10
    const auto [quotient_1024, remainder_1024] = (product_sum + add_right).divmod(modulus);
3351
3352
10
    return quotient_1024.lo;
3353
10
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_SI_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_SI_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_SF_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_SF_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINSA_9uint256_tEEESaISD_EESH_SH_
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E30compute_maximum_quotient_valueERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_SG_
3354
template <typename Builder, typename T>
3355
std::pair<bool, size_t> bigfield<Builder, T>::get_quotient_reduction_info(const std::vector<uint512_t>& as_max,
3356
                                                                          const std::vector<uint512_t>& bs_max,
3357
                                                                          const std::vector<bigfield>& to_add,
3358
                                                                          const std::vector<uint1024_t>& remainders_max)
3359
1.20M
{
3360
1.20M
    ASSERT(as_max.size() == bs_max.size());
3361
3362
1.20M
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
1.20M
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
1.20M
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
1.20M
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
1.20M
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
1.20M
    std::vector<uint512_t> to_add_max;
3372
1.69M
    for (auto& added_element : to_add) {
3373
1.69M
        to_add_max.push_back(added_element.get_maximum_value());
3374
1.69M
    }
3375
    // Get maximum value of quotient
3376
1.20M
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
1.20M
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
5
        return std::pair<bool, size_t>(true, 0);
3381
5
    }
3382
1.20M
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
1.20M
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_RKS7_IS6_SaIS6_EERKS7_INS9_ISB_EESaISK_EE
Line
Count
Source
3359
1.10M
{
3360
1.10M
    ASSERT(as_max.size() == bs_max.size());
3361
3362
1.10M
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
1.10M
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
1.10M
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
1.10M
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
1.10M
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
1.10M
    std::vector<uint512_t> to_add_max;
3372
1.56M
    for (auto& added_element : to_add) {
3373
1.56M
        to_add_max.push_back(added_element.get_maximum_value());
3374
1.56M
    }
3375
    // Get maximum value of quotient
3376
1.10M
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
1.10M
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
5
        return std::pair<bool, size_t>(true, 0);
3381
5
    }
3382
1.10M
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
1.10M
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_RKS7_IS6_SaIS6_EERKS7_INS9_ISB_EESaISK_EE
Line
Count
Source
3359
38
{
3360
38
    ASSERT(as_max.size() == bs_max.size());
3361
3362
38
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
38
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
38
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
38
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
38
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
38
    std::vector<uint512_t> to_add_max;
3372
38
    for (auto& added_element : to_add) {
3373
0
        to_add_max.push_back(added_element.get_maximum_value());
3374
0
    }
3375
    // Get maximum value of quotient
3376
38
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
38
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
38
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
38
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSA_9uint256_tEEESaISD_EESH_RKS9_IS8_SaIS8_EERKS9_INSB_ISD_EESaISM_EE
Line
Count
Source
3359
16
{
3360
16
    ASSERT(as_max.size() == bs_max.size());
3361
3362
16
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
16
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
16
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
16
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
16
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
16
    std::vector<uint512_t> to_add_max;
3372
16
    for (auto& added_element : to_add) {
3373
0
        to_add_max.push_back(added_element.get_maximum_value());
3374
0
    }
3375
    // Get maximum value of quotient
3376
16
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
16
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
16
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
16
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE
Line
Count
Source
3359
4.01k
{
3360
4.01k
    ASSERT(as_max.size() == bs_max.size());
3361
3362
4.01k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
4.01k
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
4.01k
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
4.01k
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
4.01k
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
4.01k
    std::vector<uint512_t> to_add_max;
3372
5.10k
    for (auto& added_element : to_add) {
3373
5.10k
        to_add_max.push_back(added_element.get_maximum_value());
3374
5.10k
    }
3375
    // Get maximum value of quotient
3376
4.01k
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
4.01k
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
4.01k
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
4.01k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256k18FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE
Line
Count
Source
3359
27
{
3360
27
    ASSERT(as_max.size() == bs_max.size());
3361
3362
27
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
27
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
27
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
27
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
27
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
27
    std::vector<uint512_t> to_add_max;
3372
27
    for (auto& added_element : to_add) {
3373
26
        to_add_max.push_back(added_element.get_maximum_value());
3374
26
    }
3375
    // Get maximum value of quotient
3376
27
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
27
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
27
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
27
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_RKSA_IS9_SaIS9_EERKSA_INSC_ISE_EESaISN_EE
Line
Count
Source
3359
86.4k
{
3360
86.4k
    ASSERT(as_max.size() == bs_max.size());
3361
3362
86.4k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
86.4k
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
86.4k
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
86.4k
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
86.4k
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
86.4k
    std::vector<uint512_t> to_add_max;
3372
114k
    for (auto& added_element : to_add) {
3373
114k
        to_add_max.push_back(added_element.get_maximum_value());
3374
114k
    }
3375
    // Get maximum value of quotient
3376
86.4k
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
86.4k
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
86.4k
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
86.4k
}
_ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256k18FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_RKSA_IS9_SaIS9_EERKSA_INSC_ISE_EESaISN_EE
Line
Count
Source
3359
576
{
3360
576
    ASSERT(as_max.size() == bs_max.size());
3361
3362
576
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
576
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
576
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
576
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
576
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
576
    std::vector<uint512_t> to_add_max;
3372
576
    for (auto& added_element : to_add) {
3373
576
        to_add_max.push_back(added_element.get_maximum_value());
3374
576
    }
3375
    // Get maximum value of quotient
3376
576
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
576
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
576
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
576
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE
Line
Count
Source
3359
5.56k
{
3360
5.56k
    ASSERT(as_max.size() == bs_max.size());
3361
3362
5.56k
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
5.56k
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
5.56k
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
5.56k
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
5.56k
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
5.56k
    std::vector<uint512_t> to_add_max;
3372
9.04k
    for (auto& added_element : to_add) {
3373
9.04k
        to_add_max.push_back(added_element.get_maximum_value());
3374
9.04k
    }
3375
    // Get maximum value of quotient
3376
5.56k
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
5.56k
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
5.56k
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
5.56k
}
_ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_9secp256r18FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE
Line
Count
Source
3359
10
{
3360
10
    ASSERT(as_max.size() == bs_max.size());
3361
3362
10
    ASSERT(to_add.size() <= MAXIMUM_SUMMAND_COUNT);
3363
10
    ASSERT(as_max.size() <= MAXIMUM_SUMMAND_COUNT);
3364
10
    ASSERT(remainders_max.size() <= MAXIMUM_SUMMAND_COUNT);
3365
3366
    // Check if the product sum can overflow CRT modulus
3367
10
    if (mul_product_overflows_crt_modulus(as_max, bs_max, to_add)) {
3368
0
        return std::pair<bool, size_t>(true, 0);
3369
0
    }
3370
10
    const size_t num_quotient_bits = get_quotient_max_bits(remainders_max);
3371
10
    std::vector<uint512_t> to_add_max;
3372
10
    for (auto& added_element : to_add) {
3373
10
        to_add_max.push_back(added_element.get_maximum_value());
3374
10
    }
3375
    // Get maximum value of quotient
3376
10
    const uint512_t maximum_quotient = compute_maximum_quotient_value(as_max, bs_max, to_add_max);
3377
3378
    // Check if the quotient can fit into the range proof
3379
10
    if (maximum_quotient >= (uint512_t(1) << num_quotient_bits)) {
3380
0
        return std::pair<bool, size_t>(true, 0);
3381
0
    }
3382
10
    return std::pair<bool, size_t>(false, num_quotient_bits);
3383
10
}
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_RKSA_IS9_SaIS9_EERKSA_INSC_ISE_EESaISN_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_9secp256r18FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSB_9uint256_tEEESaISE_EESI_RKSA_IS9_SaIS9_EERKSA_INSC_ISE_EESaISN_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_RKS7_IS6_SaIS6_EERKS7_INS9_ISB_EESaISK_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_20UltraCircuitBuilder_INS_25UltraExecutionTraceBlocksEEENS_13Bn254FrParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS8_9uint256_tEEESaISB_EESF_RKS7_IS6_SaIS6_EERKS7_INS9_ISB_EESaISK_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEENS_13Bn254FqParamsEE27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINSA_9uint256_tEEESaISD_EESH_RKS9_IS8_SaIS8_EERKS9_INSB_ISD_EESaISM_EE
Unexecuted instantiation: _ZN2bb6stdlib8bigfieldINS_19MegaCircuitBuilder_INS_5fieldINS_13Bn254FrParamsEEEEES4_E27get_quotient_reduction_infoERKSt6vectorINS_7numeric5uintxINS9_9uint256_tEEESaISC_EESG_RKS8_IS7_SaIS7_EERKS8_INSA_ISC_EESaISL_EE
3384
3385
} // namespace bb::stdlib